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

本文围绕Shiro设置session过期时间无效问题展开。先介绍Shiro的SessionManager,包括Servlet Container Session和Native Session两种类型及对应过期时间指定方式。接着重现bug,指出ehcache自行删除session导致过期时间设置无效。最后总结应让session调度器负责检查和删除,缓存只存储。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景知识

虽然本文主要是讲述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="120" 
timeToLiveSeconds="1800" 
overflowToDisk="false"/>

这样配置有2个错误。

以上两种错误,都是ehcache自作主张导致session未过期而删除,未通知session调度器。正确的做法是只有session调度器 有权删除,ehcache不能自行删除,这就要求ehcache中session的空闲时间为永久、如果内存不够就写到磁盘,如果要求重启jvm session不丢失,还需要diskPersistent=true。顺便说一下,session调度器默认是每隔1小时,执行一次。
正确的配置应该为

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

其实在shiro-ehcache.jar中,有个ehcache.xml(对应java中的net.sf.ehcache.config.CacheConfiguration),里边的注释也明确说明了这个问题

 <!-- 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"/>

总结

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

参考

shiro session management

评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值