前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >shiro和spring整合

shiro和spring整合

作者头像
sucl
发布2019-08-07 11:49:36
6580
发布2019-08-07 11:49:36
举报
文章被收录于专栏:企业平台构建企业平台构建

之前用shiro参考官网写了简单的示例,对于shiro我们大致可以了解其主要的构造,网上有很多这样的示例,但是对于开发者来说,我们需要做的很少,可以说大部分模块都已经由框架本身帮助我们实现,我们需要关注的仅仅是框架开放且无法实现的模块,即验证模型构建,而java基本都是以面向接口未核心,那么我只需要完成核心接口的实现即可。

目前对于shiro的扩展主要包括以下几个部分:

1、过滤器的定义与实现。主要分为认证与鉴权两种,官方提供的认证过滤器有:anon、authc、authcBasic、user;鉴权包括:perms、port、rest、roles、ssl。我们可以根据自己的业务需求,对原有的过滤器进行扩展与重写。

2、token的自定义。一般用的token都是UsernamePasswordToken,这个基本可以帮我们实现用户名、密码这种模式的校验,但是有时候登录有多种参数,比如验证码、动态码等,可以通过自己扩展来实现。

3、realm的实现。这里就需要我们实现官方提供的接口AuthorizingRealm,里面有认证和授权的方法需要由我们实现,而我们需要做的就是构建认证与授权的模型,分别是AuthenticationInfo、AuthorizationInfo,具体的密码比对与角色权限验证都是框架实现,只要我们按照规范的模式进行模型的构造即可,这也是一种良好的设计思路。

4、session的管理。一般情况使用的是DefaultSessionManager,可以通过重定义其属性SessionDao来实现session的持久化管理,主要用于分布式保证会话一致性。

大体上学会这几个方面的内容也就可以针对实际业务通过shiro实现安全认证方面的功能了。

shiro和spring整合主要是由spring管理关键的对象,项目通过maven构建管理,相应pom文件主要引入shiro核心包与spring核心包

代码语言:javascript
复制
   <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.7</java.version>
        <spring.version>4.2.6.RELEASE</spring.version>
        <shiro.version>1.4.0</shiro.version>
        <mysql.version>5.1.29</mysql.version>
    </properties>

    <dependencies>
        <!--test-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
            <scope>test</scope>
        </dependency>
        <!--shiro-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>1.4.0-RC2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-web</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <!--spring-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>
<!--    <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring.version}</version>
        </dependency>-->
        <!--aop-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.7.1</version>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.5</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.1</version>
        </dependency>
        <!--db-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.18</version>
        </dependency>
        <!--commons-->
        <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils-core</artifactId>
            <version>1.8.3</version>
        </dependency>
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.10</version>
        </dependency>
        <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.2.2</version>
        </dependency>
        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>1.4</version>
        </dependency>
        <dependency>
            <groupId>commons-httpclient</groupId>
            <artifactId>commons-httpclient</artifactId>
            <version>3.1</version>
        </dependency>
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.1</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
        </dependency>
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.3</version>
        </dependency>
        <dependency>
            <groupId>commons-pool</groupId>
            <artifactId>commons-pool</artifactId>
            <version>1.6</version>
        </dependency>
        <!--log-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.16</version>
        </dependency>
        <!--json-->
        <dependency>
            <groupId>net.sf.json-lib</groupId>
            <artifactId>json-lib</artifactId>
            <version>2.4</version>
            <classifier>jdk15</classifier>
        </dependency>
        <!--jwt-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.0</version>
        </dependency>
        <!--servlet-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.3.1</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

其次就是web.xml文件,主要设置相关的过滤器,这样才能在登录或访问页面时进入到相关的过滤器链中,实现登录权限校验:

代码语言:javascript
复制
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/configs/spring-context.xml</param-value>
	</context-param>
	
	<filter>
		<filter-name>encodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<async-supported>true</async-supported>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>encodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

	<filter>
		<filter-name>shiroFilter</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>shiroFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	
	<servlet>
		<servlet-name>SpringMVC</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/configs/spring-mvc.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>SpringMVC</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
	
	<welcome-file-list>
		<welcome-file>/index.html</welcome-file>
	</welcome-file-list>

	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	<listener>
		<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
	</listener>

使用的是springmvc,也引入了mvc的请求分发器。

最后就是spring上下文与shiro核心bean的引入了:

代码语言:javascript
复制
    <bean id="formAuthc" class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter"/>

    <bean id="authenticator" class="org.apache.shiro.authc.pam.ModularRealmAuthenticator">
        <property name="authenticationStrategy">
            <!-- 多个Reaml认证中有一个认证成功即成功策略 -->
            <bean class="org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy"></bean>
            <!-- 第一个Reaml认证策略 -->
            <!-- <bean class="org.apache.shiro.authc.pam.FirstSuccessfulStrategy"></bean> -->
            <!-- 必须所有Reaml都成功认证策略  -->
            <!-- <bean class="org.apache.shiro.authc.pam.AllSuccessfulStrategy"></bean> -->
        </property>
<!--        <property name="realms">
            <list>
                <ref bean="otherRealm"/>
                <ref bean="defaultRealm"/>
            </list>
        </property>-->
    </bean>

	<!-- 继承自AuthorizingRealm的自定义Realm,即指定Shiro验证用户登录的类为自定义的UserRealm.java -->
	<bean id="defaultRealm" class="com.sucl.shirosecurity.security.DefaultRealm"/>
    <bean id="otherRealm" class="com.sucl.shirosecurity.security.OtherRealm"/>

	<!-- Shiro主过滤器本身功能十分强大,其强大之处就在于它支持任何基于URL路径表达式的、自定义的过滤器的执行 -->
	<!-- Web应用中,Shiro可控制的Web请求必须经过Shiro主过滤器的拦截,Shiro对基于Spring的Web应用提供了完美的支持 -->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<!-- Shiro的核心安全接口,这个属性是必须的 -->
		<property name="securityManager" ref="securityManager"/>
		<!-- 要求登录时的链接(可根据项目的URL进行替换),非必须的属性,默认会自动寻找Web工程根目录下的"/login.html"页面 -->
		<property name="loginUrl" value="/login.jsp"/>
		<!-- 登录成功后要跳转的连接 -->
		<property name="successUrl" value="/index.jsp"/>
		<!-- 用户访问未对其授权的资源时,所显示的连接 -->
		<!-- 若想更明显的测试此属性可以修改它的值,如unauthor.jsp,然后用[玄玉]登录后访问/admin/listUser.jsp就看见浏览器会显示unauthor.jsp -->
		<!-- <property name="unauthorizedUrl" value="/no_permissions.jsp" />  -->
		<!-- Shiro连接约束配置,即过滤链的定义 -->
		<!-- 此处可配合我的这篇文章来理解各个过滤连的作用http://blog.csdn.net/jadyer/article/details/12172839 -->
		<!-- 下面value值的第一个'/'代表的路径是相对于HttpServletRequest.getContextPath()的值来的 -->
		<!-- anon:它对应的过滤器里面是空的,什么都没做,这里.do和.jsp后面的*表示参数,比方说login.jsp?main这种 -->
		<!-- authc:该过滤器下的页面必须验证后才能访问,它是Shiro内置的一个拦截器org.apache.shiro.web.filter.authc.FormAuthenticationFilter -->
		<property name="filterChainDefinitions">
			<value>
				<!-- anon表示此地址不需要任何权限即可访问 -->
				/css/** = anon
				/js/** = anon
				/images/** = anon
				/login.jsp = formAuthc
				/authc.jsp = roles[admin]
                /logout = logout
				/** = authc
			</value>
		</property>
	</bean>

	<!-- Shiro默认会使用Servlet容器的Session,可通过sessionMode属性来指定使用Shiro原生Session -->
	<!-- 即<property name="sessionMode" value="native"/>,详细说明见官方文档 -->
	<!-- 这里主要是设置自定义的单Realm应用,若有多个Realm,可使用'realms'属性代替 -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<!-- Shiro 多Realm认证策略 -->
		<property name="authenticator" ref="authenticator"></property>

		<property name="sessionManager" ref="sessionManager"></property>
		<!--<property name="realm" ref="defaultRealm"/>-->
		<!-- 多Realm Bean 引用 -->
		<property name="realms">
			<list>
				<ref bean="defaultRealm"></ref>
				<ref bean="otherRealm"></ref>
			</list>
		</property>
		<property name="rememberMeManager" ref="rememberManager"></property>
	</bean>

	<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
		<!--session超时时间-->
		<property name="globalSessionTimeout" value="3600000"></property>
		<!--session缓存-->
		<property name="cacheManager" ref="cacheManager"></property>
		<!--删除失效session-->
		<property name="deleteInvalidSessions" value="true"></property>
		<!--session校验器-->
		<property name="sessionValidationSchedulerEnabled" value="true"></property>
		<!--session本地存储-->
		<property name="sessionDAO" ref="sessionDao"></property>
		<!--是否将sessionId存储到cookie-->
		<property name="sessionIdCookieEnabled" value="true"></property>
		<!--默认cookie存储的值-->
		<!--<property name="sessionIdCookie" value="sessionIdCookie"></property>-->
	</bean>

	<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
		<property name="cacheManagerConfigFile" value="classpath:encache.xml"></property>
	</bean>

	<bean id="sessionDao" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO">
		<property name="cacheManager" ref="cacheManager"></property>
	</bean>

	<!--CookieRememberMeManager-->
	<bean id="rememberManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
		<property name="cookie" ref="simpleCookie"></property>
		<property name="cipherKey" value="#{T(org.apache.shiro.codec.Base64).decode('2AvVhdsgUs0FSA3SDFAdag==')}"></property>
	</bean>

	<bean id="simpleCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
		<property name="httpOnly" value="true"></property>
		<property name="maxAge" value="180000"></property>
		<property name="name" value="rememberMe"></property>
	</bean>

	<!-- Shiro生命周期处理器 -->
	<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
	<!-- 开启shiro注解-->
	<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
		  depends-on="lifecycleBeanPostProcessor">
		<property name="proxyTargetClass" value="true" />
	</bean>
	<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
		<property name="securityManager" ref="securityManager"/>
	</bean>

比较核心的有shiroFilter,这个和web.xml中名称要一致,其属性可以看该类的属性,对于必须的属性我们需要配置进去,有默认值的可以直接使用。

securityManager,这个作为shiro的核心,也需要我们进行管理或扩展,realm就是在这里管理的。

整体的流程如下:

1、定义登录请求与页面,比如定义了/login.jsp,可以配置其由authc拦截,也就是org.apache.shiro.web.filter.authc.FormAuthenticationFilter,页面中需要定义相关参数,如username、password,该名称必须固定;form请求必须为post类型,提交地址必须为login.jsp,或者为空。

2、登录请求提交后则由authc进行登录,主要是调用我们配置的realm其中的doGetAuthenticationInfo方法,该方法返回AuthenticationInfo对象,该对象主要包含principal、credential,其中principal可以随便定义,但是根据业务需求可以进行扩展,因为在SecurityUtils.getSubject().getPrincipals()中可以拿到,其次在权限校验的时候要用到该对象;credential必须与密码一致,这个框架会校验。

3、若有多个realm,即验证的方式有多样化,比如多表、数据库令牌验证等等,此时需要在shiro.xml中配置authenticator。关于多方式认证,一是可以通过构建多个realm,或者通过一个realm构建不同的principal,结合token实现。

本次示例地址:shiro-security

下次使用springboot与shiro整合,大体上应该差不多。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
验证码
腾讯云新一代行为验证码(Captcha),基于十道安全栅栏, 为网页、App、小程序开发者打造立体、全面的人机验证。最大程度保护注册登录、活动秒杀、点赞发帖、数据保护等各大场景下业务安全的同时,提供更精细化的用户体验。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档