前言
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接口接口