spring与shrio集成记录
来源:互联网 发布:手机照片搞怪软件 编辑:程序博客网 时间:2024/06/03 21:37
写在前面
shrio断断续续看了有几周了,当初从jeesite项目里面知道有这么一个东东存在,然后网上看到开涛的博客,于是就跟着他的博客挑自己感兴趣的看,都是零零散散的看,虽然整合起来了,还是有一些细节我可能没有注意到,等到用到再补上就好了。
代码
pom.xml shiro部分
<shiro.version>1.2.2</shiro.version> <shiro.version>1.2.3</shiro.version> 1.2.2和1.2.3架包还是有点区别的,使用时候一定要注意! <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId> <version>${shiro.version}</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>${shiro.version}</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-quartz</artifactId> <version>${shiro.version}</version> </dependency>
web.xml shiro 部分
<!--Shiro对Servlet容器的FilterChain进行了代理,先执行Shiro自己的Filter链;2、再执行Servlet容器的Filter链(即原始的Filter)--><filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
spring-shiro.xml 内容
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd" default-lazy-init="true"> <description>Shiro Configuration</description> <!-- 【1】定义Shiro安全管理配置 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="systemAuthorizingRealm" /> <property name="sessionManager" ref="sessionManager" /> <property name="cacheManager" ref="shiroCacheManager" /> </bean> <!-- 【1.1】Realm实现 --> <bean id="systemAuthorizingRealm" class="com.msok.common.utils.SystemAuthorizingRealm"> <property name="credentialsMatcher" ref="credentialsMatcher" /> <property name="cachingEnabled" value="true" /> <property name="authenticationCachingEnabled" value="true" /> <property name="authenticationCacheName" value="authenticationCache" /> <property name="authorizationCachingEnabled" value="true" /> <property name="authorizationCacheName" value="authorizationCache" /> </bean> <!-- 【1.1.1】凭证匹配器 可以自定义。利用这个将密码进行解密验证 --> <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"> <property name="hashAlgorithmName" value="md5" /> <property name="hashIterations" value="2" /> </bean> <!-- 【1】安全认证过滤器 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <!-- shiro的核心安全接口 --> <property name="securityManager" ref="securityManager" /><!-- 要求登录时的链接 --> <property name="loginUrl" value="/msok/web/login" /> <!-- 登陆成功后要跳转的连接 如果首先访问受保护 URL 登录成功,则跳转到实际访问页面 --> <property name="successUrl" value="/msok/web/success" /> <!--可以在代码里面配置 --> <property name="unauthorizedUrl" value="/msok/web/unauthorizedUrl" /> <property name="filters"> <map> <!-- <entry key="cas" value-ref="casFilter"/> --> <entry key="authc" value-ref="formAuthenticationFilter" /> </map> </property> <!-- shiro连接约束配置 --> <property name="filterChainDefinitions"> <ref bean="shiroFilterChainDefinitions" /> </property> </bean> <!-- 加载配置属性文件 --> <!-- Shiro权限过滤过滤器定义 authc 表示需要认证 anon 表示匿名访问(不需要认证与授权)perms[SECURITY_ACCOUNT_VIEW] 表示用户需要提供值为“SECURITY_ACCOUNT_VIEW”Permission 信息 --> <!-- user用户拦截器,用户已经身份验证/记住我登录的都可;示例“/**=user” --> <!-- authc基于表单的拦截器;如“/**=authc”,如果没有登录会跳到相应的登录页面登录;表单提交的用户名参数名( username); passwordParam:表单提交的密码参数名(password); rememberMeParam:表单提交的密码参数名 --> <!-- logout退出拦截器,主要属性:redirectUrl:退出成功后重定向的地址(/);示例“/logout=logout” --> <!-- anon 匿名拦截器,即不需要登录即可访问;一般用于静态资源过滤;示例“/static/**=anon” --> <!-- 授权相关的 --> <!-- roles 角色授权拦截器,验证用户是否拥有所有角色;主要属性: loginUrl:登录页面地址(/login.jsp);unauthorizedUrl:未授权后重定向的地址;示例“/admin/**=roles[admin]” perms 权限授权拦截器,验证用户是否拥有所有权限;属性和roles一样;示例“/user/**=perms["user:create"]” --> <bean name="shiroFilterChainDefinitions" class="java.lang.String"> <constructor-arg> <value> /static/** = anon /msok/web/login = authc /msok/web/** = user /gencodeplatform/gencode/** = rest[student] <!--/logout = logout gencodeplatform/gencode/**=rest[test] --> </value> </constructor-arg> </bean> <!-- 基于Form表单的身份验证过滤器--> <bean id="formAuthenticationFilter" class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter"> <property name="usernameParam" value="username" /> <property name="passwordParam" value="password" /> </bean> <!-- CAS认证过滤器 <bean id="casFilter" class="org.apache.shiro.cas.CasFilter"> <property name="failureUrl" value="${adminPath}/login"/> </bean> --> <!-- 会话管理器 也可以自定义。定时删除啊什么的 --> <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"> <property name="globalSessionTimeout" value="1800000" /> <property name="deleteInvalidSessions" value="true" /> <!-- 定时清理失效会话, 清理用户直接关闭浏览器造成的孤立会话 --> <property name="sessionValidationSchedulerEnabled" value="true" /> <!-- 配置了这个那么sessionValidationInterval 就不用配置了 <property name="sessionValidationScheduler" ref="sessionValidationScheduler" /> --> <property name="sessionValidationInterval" value="1800000" /> <property name="sessionDAO" ref="sessionDAO" /> <property name="sessionIdCookieEnabled" value="true" /> <!-- sessionid 生成规则 --> <property name="sessionIdCookie" ref="sessionIdCookie" /> </bean> <!-- 会话验证调度器 --> <bean id="sessionValidationScheduler" class="org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler"> <property name="sessionValidationInterval" value="1800000" /> <property name="sessionManager" ref="sessionManager" /> </bean> <!-- 会话Cookie模板 --> <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie"> <constructor-arg value="sid" /> <property name="httpOnly" value="true" /> <property name="maxAge" value="180000" /> </bean> <!-- 自定义Session存储容器 不是所有的连接都要创建session,所以我们自定义dao <bean id="sessionDAO" class="com.msok.common.utils.CacheSessionDAO">--> <bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO"> <property name="sessionIdGenerator" ref="sessionIdGenerator" /> <!-- activeSessionsCache 缓存名称 --> <property name="activeSessionsCacheName" value="activeSessionsCache" /> <property name="cacheManager" ref="shiroCacheManager" /> </bean> <!-- 会话ID生成器 可以自定义 --> <bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator" /> <!-- 定义授权缓存管理器 --> <bean id="shiroCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> <property name="cacheManager" ref="cacheManager" /> </bean> <!-- 保证实现了Shiro内部lifecycle函数的bean执行 --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" /> <!-- AOP式方法级权限检查 启用Shiro注解(例如,@RequiresRoles,@RequiresPermissions 等等 --> <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> <!-- 支持Shiro对Controller的方法级AOP安全控制 end --></beans>
配置说明
shiro-web 也是在web.xml里面配置filter。 它可以在spring拦截之前进行拦截处理。
shrio很多类都有默认的,我们可以继承他们然后重写我们需要的方法,这个非常重要,所以说每一个用到的类我们都要注意下
拦截器
Shiro对Servlet容器的FilterChain进行了代理,先执行Shiro自己的Filter链;2、再执行Servlet容器的Filter链(即原始的Filter)也就是说shiro的拦截器会在spring拦截之前进行拦截,拦截优先级最高。
配置内容比较多,我们一行一行来解释。
securityManager:安全管理器
loginUrl:
登陆地址,比如我们访问一个url,而这个url是处于shiro拦截的,如果这个时候该用户没有登陆,那么就会跳转到此loginUrl,默认访问方式GET,这个loginUrl 可以是一个具体的login.jsp,也可以是controller里面 某个方法映射的地址 /msok/web/login。但是我们推荐用第二种也就是方法映射的地址。因为有时候用户已经登陆过了,就没有必要再重复进行登陆了,我们可以在controller方法里面进行相关的处理。
successUrl :
是你登陆成功之后要访问的地址,如果你登陆时候 输入的地址不是loginUrl ,而是一个受保护的地址,那么登陆成功之后 就会直接跳转到这个受保护的地址。举个例子 比如loginurl=/login ,successUlr=/index 如果你在浏览器敲 /login进行登陆,那么登陆成功之后肯定是跳转到/index ,可是如果你在浏览器敲/test,那么登陆成功之后访问的就是/test。
unauthorizedUrl :
是该用户没有权限访问这个地址,跳转到的地址。如果我们在controller层增加了注解异常@ExceptionHandler({ UnauthorizedException.class }),那么这个unauthorizedUrl 也可以忽略掉
shiroFilterChainDefinitions:
shiroFilterChainDefinitions里面配置的是一些拦截地址和拦截处理对应的类。
我们需要注意的就是:
/msok/web/login = authc 这个地址必须要和loginUrl=/msok/web/login 一样,而且提交表单地址的页面也是/msok/web/login 不过方法是POST形式
<!-- 加载配置属性文件 --> <!-- Shiro权限过滤过滤器定义 authc 表示需要认证 anon 表示匿名访问(不需要认证与授权)perms[SECURITY_ACCOUNT_VIEW] 表示用户需要提供值为“SECURITY_ACCOUNT_VIEW”Permission 信息 --> <!-- user用户拦截器,用户已经身份验证/记住我登录的都可;示例“/**=user” --> <!-- authc基于表单的拦截器;如“/**=authc”,如果没有登录会跳到相应的登录页面登录;表单提交的用户名参数名( username); passwordParam:表单提交的密码参数名(password); rememberMeParam:表单提交的密码参数名 --> <!-- logout退出拦截器,主要属性:redirectUrl:退出成功后重定向的地址(/);示例“/logout=logout” --> <!-- anon 匿名拦截器,即不需要登录即可访问;一般用于静态资源过滤;示例“/static/**=anon” --> <!-- 授权相关的 --> <!-- roles 角色授权拦截器,验证用户是否拥有所有角色;主要属性: loginUrl:登录页面地址(/login.jsp);unauthorizedUrl:未授权后重定向的地址;示例“/admin/**=roles[admin]” perms 权限授权拦截器,验证用户是否拥有所有权限;属性和roles一样;示例“/user/**=perms["user:create"]” -->
formAuthenticationFilter:
登陆时候的表单验证器,我们可以重写。
认证和授权
这是一段配置认证和授权的配置文件片断。
我们在页面输入用户名和密码之后肯定要进入后台进行验证,AuthorizingRealm类就是这样的一个入口,提供验证和授权的两个方法
doGetAuthenticationInfo(AuthenticationToken token)=验证
doGetAuthorizationInfo(PrincipalCollection principals)=授权
AuthenticationToken 里面保存的用户前台输入的用户名和密码
token.getPrincipal()等于用户名,token.getCredentials()等于前台输入的密码。
后台密码一般都是进行加密的,这时候就涉及到加密解密了。shiro提供多种加密方式,具体学习地址可以参考开涛博客第五章 编码/加密——《跟我学Shiro》
我们前台传过去的密码一般都是明文,然后我们后台调用数据库查询出来加密的密码,然后利用shiro的credentialsMatcher 密码验证器,将明文按照规定的规则进行加密,再和数据库里面的进行匹配,下面的这个就是验证方法doGetAuthenticationInfo()返回的参数AuthenticationInfo。它有这几个部分组成,(用户名,密码,盐,realmName)对应SimpleAuthenticationInfo里面参数
return new SimpleAuthenticationInfo(username, password, ByteSource.Util.bytes(**salt**), getName());
也许对盐salt的概念都比较陌生,这里就又涉及到加密的一些知识点了,常见的MD5或者SHA 加密的后的密码如果比较常见可能被暴力破解掉,
如果我们在进行散列算法生成密码时候加入一些干扰元素盐,这样就不容易被逆向了。
散列规则我们可以这样弄:密码+用户名+盐+散列2次
密码+username+salt+2=md5后密码
用java代码来写就是这样
String password=new SimpleHash("md5", "密码", ByteSource.Util.bytes(salt), 2).toHex();
既然我们验证是这样写的,那么我们在注册时候肯定要将密码及盐保存到数据库里面去,salt我们可以用一个随机数
String salt2 = new SecureRandomNumberGenerator().nextBytes().toHex();
如果为了防止暴力破解,比如密码输入五次就不让继续登陆了,我们可以在重写HashedCredentialsMatcher,也就是配置文件里面的bean为credentialsMatcher的类,然后重写doCredentialsMatch()方法,比如密码认证失败一次就放到缓存里面累加一次。具体可以参考RetryLimitHashedCredentialsMatcher.java代码。
以上说的是验证获取AuthenticationInfo的过程进行验证,shrio提供了authorizationCaching和authenticationCaching 也就是验证和授权的缓存。shiro-spring-1.2.2架包配置文件里面默认是不开启的,所以如果我们要开启就需要手动添加 可以看配置文件截图,shiro-spring-1.2.3架包里面默认是开启的。
我们看这个截图,这是进行密码验证时候首先是查询缓存里面有没有AuthenticationInfo,如果没有那就调用doGetAuthenticationInfo()方法
AuthenticatingRealm.java
密码验证成功了 那么就当然进行授权步骤了,授权步骤调用的doGetAuthorizationInfo方法,当然这里面也有缓存机制,原理看下图把
当我们手动调用检查是否有权限的时候 也会先从缓存里面查询
doGetAuthorizationInfo里面主要是进行授权功能的,在这个方法里面,我们需要调用数据库,查询改用户有哪些角色和权限,然后放到SimpleAuthorizationInfo 里面去。
SimpleAuthorizationInfo sai = new SimpleAuthorizationInfo();sai.setStringPermissions(permissionsSet);
以下截图是模拟查询数据库,获取相应按钮角色和权限。
会话管理
Shiro提供了完整的企业级会话管理功能,不依赖于底层容器(如web容器tomcat),不管JavaSE还是JavaEE环境都可以使用,提供了会话管理、会话事件监听、会话存储/持久化、容器无关的集群、失效/过期支持、对Web的透明支持、SSO单点登录的支持等特性。即直接使用Shiro的会话管理可以直接替换如Web容器的会话管理。
会话管理器有以下几个部分组成,下图ref的部分,也就是
会话监听器,会话监听器用于监听会话创建、过期及停止事件
会话存储/持久化(SessionDAO) ,Shiro提供SessionDAO用于会话的CRUD
会话验证(sessionValidationScheduler),Shiro提供了会话验证调度器,用于定期的验证会话是否已过期,如果过期将停止会话。可以Quartz会话验证调度器
我们也可以自定义sessiondao 然后将session放到缓存里面或者存放到数据库里面去。
Shiro安全管理器
Shiro安全管理器主要维护 realm 和sessionManager 还有通用的缓存cacheManager
shiro注解aop
配置注解这样我们在controller就可以直接在方法上面 增加权限的校验,如果没有直接权限就无法调用此方法
例如 @RequiresPermissions(value = “bb:test”)
遇到问题
退出浏览器之后,直接登录页面发现不需要登陆就可以进入,定位半天发现是cookie搞的鬼,注释掉这段就可以了。
<!-- 会话Cookie模板 --> <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie"> <constructor-arg value="sid" /> <!-- 设置cookie生效时间,默认是退出浏览器cookie就消失 <property name="httpOnly" value="true" /> <property name="maxAge" value="180000" /> --> </bean>
- spring与shrio集成记录
- springmvc集成shrio
- Redis-shrio集成
- Shrio 入门系列 三 (授权与Spring整合)
- 记录spring集成mongodb
- CXF与Spring集成:自定义验证权限以及日志记录
- 使用shrio保护spring 应用
- spring boot+redis+shrio+会话
- springmvc+spring+mybatis+shrio+mysql
- Spring集成Monggodb记录,使用记录
- shrio
- Shrio
- Tapestry3 与 Spring 集成
- struts2.与spring集成
- CXF与spring集成
- CXF与spring集成
- CXF与spring集成
- struts2.与spring集成
- 手写输入法输入 [UIKBBlurredKeyView candidateList]
- BZOJ1017
- java两个线程打印奇数和偶数
- 彩色转灰度算法
- Broadcast和BroadCastReceiver
- spring与shrio集成记录
- VS2010 C++ 学习笔记(三) 类和对象 访问限定符 String
- Springsource tool suite(简称STS)(或Eclipse)将maven工程部署到Tomcat
- select下拉框默认选择
- Java SE 学习笔记(二)
- 建立企业内部maven服务器并使用Android Studio发布公共项目
- VM WorkStation 10: 不能用ISO安装新虚拟机 (10.0.0.6)
- 1097. Deduplication on a Linked List (25)
- 类型转换