最近,将一个单一的maven项目拆分为多maven模块的项目时候, 不知道是什么原因,导致集成shiro的时候出现如下异常信息:
最后在网络上度娘了下,
1、有的说是shiro的版本问题,但是项目中因为引用了hibernate-ehcache和shiro-ehcache 这2个包,自己就带了shiro-core-2.4.3.jar包,不知道是shiro的,还是hibernate依赖的,所以,直接不用原来的shiro-core包,自己直接在maven中添加依赖shiro-core-2.4.8.jar(必须2.5.0以下的),可以解决这个问题;
2、另外就可以修改配置文件来解决:
<!-- 安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="shiroDbRealm" />
<property name="cacheManager" ref="cacheManager"/>
</bean>
<!-- 缓存管理器,使用EhCache实现-->
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<!--<property name="cacheManagerConfigFile" value="classpath:ehcache-shiro.xml"/>-->
<property name="cacheManager" ref="ehCacheManager"></property>
</bean>
将上边的的cacheManager 管理自己实现直接交给spring来实现的,并且spirng让ehcache 共享(必须);具体配置cacheManager引用如下配置即可;
<bean id="ehCacheManager" class ="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache-shiro.xml" />
<property name="shared" value="true"></property> (关键)
</bean>
这样配置也可以解决相关问题。
=======================shiro相关说明=============================================
securityManager是Shiro配置的核心,一般情况下可以做如下配置,其中只有realm是必须配置的
<!-- 安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="shiroDbRealm" />
<property name="sessionManager" ref="sessionManager"/>
<property name="cacheManager" ref="cacheManager"/>
<!--<property name="cacheManager" ref="memoryCacheManager"/>-->
</bean>
1.realm
realm中两个方法 AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken)登陆认证 和 AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals)权限验证 的实现位置,基本上都需要自己实现
个别情况下,比如当使用Shiro-Cas的时候,doGetAuthenticationInfo方法不需要自己实现
2.SessionManager
SessionManager默认是 ServletContainerSessionManager
当使用ServletContainerSessionManager时,验证登陆返回值AuthenticationInfo,中的Principal会被保存到HttpSession中,最后构造的shiro.session接口实现类中一个属性为HttpSession
如果使用DefaultWebSessionManager时,会用到SessionDAO,默认的实现是MemorySessionDAO(在其父类DefaultSessionManager中可以看到),如果使用MemorySessionDAO,Principal信息会被保存到MemorySessionDAO维护的一个 ConcurrentMap<Serializable, Session> sessions 中,如果要自己实现中央缓存,就重写该一个AbstractSessionDAO的子类并实现相关方法。
注意:
1、本地缓存通过EhCache实现,失效时间一定要远小于Redis失效时间,这样本地失效后,会访问Redis读取,并重新设置Redis上会话数据的过期时间。
2、redisSessionDao是继承CachingSessionDAO来实现,可以减少访问redis的频度;
这里有个可能出现bug的地方,可以通过配置sessionIdCookie属性,解决被服务器重写cookie中会话ID,导致会话丢失的问题(默认是“JSESSIONID”,跟tomcat和jetty一样)
<!-- sessionManager 引入session保存的Dao和session命名 -->
<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<!-- 设置全局会话超时时间,默认30分钟(1800000)-->
<property name="globalSessionTimeout" value="30000"/>
<!-- 是否在会话过期后会调用SessionDAO的delete方法删除会话 默认true-->
<property name="deleteInvalidSessions" value="true"/>
<property name="sessionDAO" ref="redisSessionDao"/>
<!-- 是否开启会话验证器任务 默认true -->
<property name="sessionValidationSchedulerEnabled" value="true"/>
<property name="sessionValidationScheduler" ref="sessionValidationScheduler"/>
<!-- 会话验证器调度时间 ,因为上边的 sessionValidationScheduler 中已经配置的调度时间,故如此处不在重复-->
<!--<property name="sessionValidationInterval" value="3600000"/>-->
<property name="sessionIdCookie" ref="sessionIdCookie"/>
</bean>
<!-- 配置session名字 避免与tomcat,jetty等session冲突默认JSESSIONID,修改用于防止访问404页面时,容器生成的标识把shiro的覆盖掉 -->
<bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
<constructor-arg name="name" value="SHIROSESSIONID"/>
</bean>
<!-- session 序列化存储 -->
<bean id="redisSessionDao" class="com.ch.bigdata.common.redis.service.RedisSessionDAO"></bean>
所以memcached-session-manager做负载均衡 和 DefaultWebSessionManager 是冲突的,可以考虑自己实现一个SessionDAO来完成负载均衡中会话管理功能
3.CacheManager
cacheManager的作用是保存doGetAuthorizationInfo(权限验证)中的返回结果,如果没有配置cacheManager,每一次权限认证都需要重新调用该方法。
======shiro 权限框架在session 失效后,点击某个链接,或刷新页面,重新登录后不跳转到成功页面====
遇到的场景是,访问项目名,类似http://localhost:8080/xxx/,shiro会通过过滤器,进入你配置的loginUrl,然后登录成功后,它会记住你之前访问的链接,那么就自然进入了http://localhost:8080/xxx/,这个时候如果你的拦截器配置(filterChainDefinitions)没有配置好/的访问权限的话,就导致页面加载不到rc.contextPath,自己配置的successUrl都没有用,除非重写formAuthenticationFilter;
解决方法见这篇文章:
http://www.cnblogs.com/sevenlin/p/sevenlin_shiro20150924.html (Shiro登录成功之后跳到指定URL)这篇文章已经说明了原因了!