shiro session设置了过期时间不起作用、无效;

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wangjun5159/article/details/89875746

背景知识

虽然本文主要是讲述shiro设置session过期时间无效问题,但是shiro的sesssion由sessionmanager管理,所以这里有必要介绍一下sessionmanager,这样有助于理解。shiro常用的sessionmanager有ServletContainerSessionManagerDefaultWebSessionManager

  • servlet container session
    设置为ServletContainerSessionManager时,session的操作由servlet容器(tomcat、jetty)负责,简单来说shiro只起桥接作用,这时的session过期时间,在web.xml中的sessiontimeout中指定;

    <session-config>
      <!-- web.xml expects the session timeout in minutes: -->
      <session-timeout>30</session-timeout>
    </session-config>
    
  • native session
    设置为 DefaultWebSessionManager时,session是native session,也就是本地session,由shiro管理session(创建、更新、销毁),跟servlet容器没有关系。这种情况时,session的过期时间在shiro配置文件中指定。

bug再现

通常我们都会选择shiro自己管理session,shiro配置配置如下


	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="cacheManager" ref="ehCacheManager" />
		<property name="sessionManager" ref="sessionManager"></property>
	</bean>
	<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
		<property name="globalSessionTimeout" value="1800000"></property>
		<property name="sessionDAO" value="enterpriseCacheSessionDAO"></property>
	</bean>
  <bean id="enterpriseCacheSessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO"/>
  <bean id="ehCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"/>

这里过期时间指定为1800000毫秒=30分钟60秒1000毫秒,也就是30分钟。
EnterpriseCacheSessionDAO的父类CachingSessionDAO,定义了缓存session的缓存块名字

public abstract class CachingSessionDAO extends AbstractSessionDAO implements CacheManagerAware {

    /**
     * The default active sessions cache name, equal to {@code shiro-activeSessionCache}.
     */
    public static final String ACTIVE_SESSION_CACHE_NAME = "shiro-activeSessionCache";
    }

所以ehcache的通常会有shiro-activeSessionCache块,配置如下

<cache name="shiro-activeSessionCache" 
maxEntriesLocalHeap="0" 
eternal="false" 
timeToIdleSeconds="1800" 
timeToLiveSeconds="1800" 
overflowToDisk="false"/>

为了与session过期时间一致,通常空闲时间和存活时间也是30分钟,如果这样配置就大错特错了!!因为这样配置,session那块内存的最大存活时间是30分钟,所以无论30分钟内,用户是否产生交互,只要到了30分钟,ehcache就会删除session!!!也就是说ehcache自行删除session,session调度器却不知道,正确的做法的应该是无论如何ehcache都不应该自行删除session,除非session调度器明确指出要删除才可以,这就要求ehcache对session这块内存,空闲时间为永久、存活时间为永久、如果内存不够就写到磁盘。by the way,session调度器默认是每隔1小时,执行一次。
正确的配置应该为

<cache name="shiro-activeSessionCache" 
maxEntriesLocalHeap="0" 
eternal="true"  <!--永久-->
timeToIdleSeconds="0" <!--空闲时间为永久-->
timeToLiveSeconds="0" <!--存活时间为永久-->
overflowToDisk="true" <!--如果内存不够则写到磁盘,持久化以防止session丢失-->
/>

其实在shiro-ehcache.jar中,有个ehcache.xml,里边的注释也明确说明了这个问题

 <!-- We want eternal="true" and no timeToIdle or timeToLive settings because Shiro manages session
         expirations explicitly.  If we set it to false and then set corresponding timeToIdle and timeToLive properties,
         ehcache would evict sessions without Shiro's knowledge, which would cause many problems
        (e.g. "My Shiro session timeout is 30 minutes - why isn't a session available after 2 minutes?"
               Answer - ehcache expired it due to the timeToIdle property set to 120 seconds.)
  
        diskPersistent=true since we want an enterprise session management feature - ability to use sessions after
        even after a JVM restart.  -->
    <cache name="shiro-activeSessionCache"
           maxElementsInMemory="10000"
           overflowToDisk="true"
           eternal="true"
           timeToLiveSeconds="0"
           timeToIdleSeconds="0"
           diskPersistent="true"
           diskExpiryThreadIntervalSeconds="600"/>

总结

  • shiro的session过期时间是由于ehcache自行删除session导致;
  • redis/ehcache与session的运作机制搞懂了。缓存只用来存储session,不能自行删除,session调度器负责check session有效性,如果过期,则明确指示redis/ehcache删除session。

参考

shiro session management

展开阅读全文

没有更多推荐了,返回首页