前言
Shiro本身提供完整的Session管理(无论是在什么环境),通过Session,可以自定义一些属性让shiro进行管理(例如可以存储密码进行定期的保存)。接下来,本篇文章会着重讲解在Shiro中如何使用Session以及Session的一些特性。
使用Session
Subject subject = SecurityUtils.getSubject();
Session session = subject.getSession();
session.setAttribute("key", "value");
和之前的代码类似,获取Session也是通过Subject对象。并且getSession()默认是调用的getSession(true)。当参数为true是,存在Session则直接返回,如果不存在则创建一个新的;当传递false时,则不创建Session。
SessionManager
从名字就可以看出,SessionManager是用来管理所有Subject的Session的,隶属于SecurityManager管理。因此可以通过配置化(shiro.ini)的形式自定义SessionManger实现。如下所示
[main]
...
sessionManager = com.mamba.bootstrap.SessionManagerImplementation
securityManager.sessionManager = $sessionManager
需要注意的是我们通常会使用Shiro自带的SessionManager。
Session timeout
Session默认也有过期时间,默认30分钟后时失效,可以通过配置的方式来设置全局失效时间
[main]
...
# 3,600,000 milliseconds = 1 hour
securityManager.sessionManager.globalSessionTimeout = 3600000
如果想要设置单个session的过期时间,则可以调用单独的setTimeout方法进行设置
Session Listeners
Shiro也支持针对Session的监听事件,可以在session启动、停止、过期等状态做出响应。针对SessionListeners的配置如下所示:
[main]
...
aSessionListener = com.mamba.sessionListener1
anotherSessionListener = com.mamba.sessionListener2
securityManager.sessionManager.sessionListeners = $aSessionListener, $anotherSessionListener.
需要注意配置的监听器是针对所有session进行配置的
Session存储
- SeesionDao:用来保存Session中的数据,可以通过实现SeesionDao决定Session数据存放的方式.关于SessionDao的配置如下:
[main]
...
sessionDAO = com.mamba.SessionDAO
securityManager.sessionManager.sessionDAO = $sessionDAO
需要注意的是,如果是在Web环境,不会默认使用SessionDao。需要进行如下声明来使用shiro自带的WebSessionManager
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
EHCache SessionDAO
- Shiro支持EhCache作为Session的存储方式,EHCache可以实现内存存储的同时溢出到磁盘来进行数据存储。如果想要开启则需要进行如下配置:
[main]
sessionDAO = org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO
securityManager.sessionManager.sessionDAO = $sessionDAO
cacheManager = org.apache.shiro.cache.ehcache.EhCacheManager
securityManager.cacheManager = $cacheManager
可以看见需要通过securityManager.cacheManager
来指定使用哪种缓存存储方式。
- 配置EhCache
shiro提供了 EhCache的默认配置ehcache.xml,内容如下:
<cache name="shiro-activeSessionCache"
maxElementsInMemory="10000"
overflowToDisk="true"
eternal="true"
timeToLiveSeconds="0"
timeToIdleSeconds="0"
diskPersistent="true"
diskExpiryThreadIntervalSeconds="600"/>
shiro也支持用户自定义缓存参数,但是需要注意的是overflowToDisk和eternal这两个参数必须要存在。并且需要指定自定义配置文件的路径
shiroCacheManager = org.apache.shiro.cache.ehcache.EhCacheManager
shiroCacheManager.cacheManagerConfigFile = classpath:conf/ehcache-shiro.xml
并且在具体使用缓存参数的时候需要指定name
sessionDAO = org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO
sessionDAO.activeSessionsCacheName = shiro-activeSessionCache
自定义Session Id
首先,Shiro默认提供了一个Session Id 生成器,使用的是JavaUuidSessionIdGenerator。如果想使用自己定义的生成器,则需要通过实现SessionIdGenerator接口,并且具体的配置如下:
[main]
...
sessionIdGenerator = com.my.session.SessionIdGenerator
securityManager.sessionManager.sessionDAO.sessionIdGenerator = $sessionIdGenerator
Session定期检查
如果没有Session的定期检查,会出现一种情况:例如用户是非正常退出登录,shiro并不知道需要关闭当前的session,久而久之session数据会被填充满。为了防止这种情况的发生,Shiro默认提供了ExecutorServiceSessionValidationScheduler来对Session定期进行检查,默认是一个小时。如果想要自定义时间,需要进行如下配置:
[main]
...
sessionValidationScheduler = org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler
# Default is 3,600,000 millis = 1 hour:
sessionValidationScheduler.interval = 3600000
securityManager.sessionManager.sessionValidationScheduler = $sessionValidationScheduler
自定义SessionValidationScheduler
如果不想使用shiro提供的默认SessionValidationScheduler,我们还可以进行指定创建,需要实现SessionValidationScheduler接口,具体的配置如下:
[main]
...
sessionValidationScheduler = com.foo.my.SessionValidationScheduler
securityManager.sessionManager.sessionValidationScheduler = $sessionValidationScheduler
禁用Session定期检查
如果默认不想使用这个功能(可能你自己通过外部的工具或者其他方式解决了这个问题),可以通过如下配置来禁用:
[main]
...
securityManager.sessionManager.sessionValidationSchedulerEnabled = false
注意这种方式只是停止了定期检查Session的数据,但是在每次查询的时候还是进行验证,如果想要彻底禁止Session检查(可能有需要查过期Session或者其他数据的需求),那么需要进行如下配置
[main]
...
securityManager.sessionManager.deleteInvalidSessions = false
需要注意的是,如果禁止删除Session。你需要自己手动进行验证,防止存储空间用光。一般情况下,都应该允许自动地Session检查
Session集群
Shiro支持Session集群的方式来存储session的数据,具体的集群方式可以指定决定(EhCache、redis等都可以实现集群)。关于如何在Shiro中触发集群的配置主要有两种方式、具体如下所示:
#This implementation would use your preferred distributed caching product's APIs:
activeSessionsCache = my.org.apache.shiro.cache.CacheImplementation
sessionDAO = org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO
sessionDAO.activeSessionsCache = $activeSessionsCache
securityManager.sessionManager.sessionDAO = $sessionDAO
这种方式通过配置SessionDao的activeSessionsCache来实现,还有一种方式如下:
cacheManager = my.org.apache.shiro.cache.CacheManagerImplementation
sessionDAO = org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO
sessionDAO.activeSessionsCacheName = shiro-activeSessionsCache
securityManager.sessionManager.sessionDAO = $sessionDAO
securityManager.cacheManager = $cacheManager
这种方式通过配置securityManager.cacheManager的来实现。
注意,关于集体如何使用存储需要自己实现Cache接口接口