目錄
shiro的SessionManager
在官方架構圖裏面:
在默認的SecurityManager的uml圖裏面:
前面的CacheSecurityManager,realmSecurityManager,認證管理器,鑑權管理器都講過了,那麼這個Session管理器是怎麼回事呢?
在web容器裏面的session跟HttpSession是同一個嗎?
首先看,我們在沒有設置Session管理器的時候,默認使用的是哪一個?
先看SessionManager的具體實現:
第一個類是AbstractNativeSessionManager,是個抽象類,主要實現就是DefaultSessionManager跟DefaultWebSessionManager,而DefaultWebSessionManager又是繼承了DefaultSessionManager,我們看一下DefaultWebSessionManager的uml圖:
WebSessionManager裏面就一個方法isServletContainerSessions判斷是否是本地會話,就是相當於判斷是不是httpSession.
再看SessionsSecurityManager,直接看我們使用的webSecurityManager:
ServletContainerSessionManager就相當於是使用HttpSession:ServletContainerSessionManager的createSession方法返回的是HttpServletSession,而HttpServletSession內部是直接維護了HttpSession對象,然後一系列方法是直接使用HttpSession進行操作的:
自定義sessionManager
看看ServletContainerSessionManager和DefaultWebSessionManager一起的uml圖:
默認的是使用的ServletContainerSessionManager,如果我們想自定義,就直接使用DefaultWebSessionManager即可了;DefaultWebSessionManager需要設置的屬性主要有:
- SessionListener,session監聽
- setSessionDAO設置sessionDao,session緩存,或者持久化
- sessionIdCookie設置cookie
- setGlobalSessionTimeout全局會話超時時間
- setDeleteInvalidSessions是否刪除無效session,默認true
- setSessionValidationSchedulerEnabled定時刪除,默認true
- setSessionValidationInterval設置多長時間檢測一下是否有過期session.然後刪除
- setSessionIdUrlRewritingEnabled是否開啓url後面加上sessionId
我們先看SessionDAO
sessionDao就是一系列的操作session的接口:
看實現:
抽象的就不看了,就三個具體實現:EnterpriseCacheSessionDAO,MemorySessionDAO,RedisSessionDAO,RedisSessionDAO就不說了比較簡單,前面說shiro使用redis緩存的時候也說過了,這個那就是session緩存在redis裏面,MemorySessionDAO也是,內部維護了一個ConcurrentMap來保存session,就是內存緩存了;EnterpriseCacheSessionDAO就是可以自己傳一個CacheManager,好比ehcache的manager,然後就將緩存存在ehcache也可以直接傳個內存緩存,也就放在內存裏面了,也可以自定義sessionid的生成器,默認是JavaUuidSessionIdGenerator也就是uuid,可以自己實現.
使用內存緩存
直接使用MemorySessionDAO:
@Bean
public SessionDAO sessionDAO() {
return new MemorySessionDAO();
}
使用ehcache
// ehcache
public SessionDAO sessionDAO() {
EnterpriseCacheSessionDAO enterpriseCacheSessionDAO = new EnterpriseCacheSessionDAO();
EhCacheManager ehCacheManager = new EhCacheManager();
ehCacheManager.setCacheManager(getEhCacheManager());
enterpriseCacheSessionDAO.setCacheManager(ehCacheManager);
enterpriseCacheSessionDAO.setActiveSessionsCacheName("shiro-activeSessionCache");
enterpriseCacheSessionDAO.setSessionIdGenerator(new JavaUuidSessionIdGenerator());
return enterpriseCacheSessionDAO;
}
使用redis
org.crazycake.shiro.RedisSessionDAO的包注意:
public SessionDAO sessionDAO() {
//redis
RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
RedisManager redisManager = new RedisManager();
redisSessionDAO.setRedisManager(redisManager);
return redisSessionDAO;
}
剩下的配置比較簡單:
/**
* 配置會話管理器,設定會話超時及保存
* @return
*/
@Bean
public SessionManager sessionManager() {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
Collection<SessionListener> listeners = new ArrayList<SessionListener>();
//配置監聽
listeners.add(new ShiroSessionListener());
sessionManager.setSessionListeners(listeners);
sessionManager.setSessionIdCookie(sessionIdCookie());
sessionManager.setSessionDAO(sessionDAO());
sessionManager.setCacheManager(new MemoryConstrainedCacheManager());
sessionManager.setGlobalSessionTimeout(10000);
sessionManager.setDeleteInvalidSessions(true);
sessionManager.setSessionValidationSchedulerEnabled(true);
sessionManager.setSessionValidationInterval(5000);
sessionManager.setSessionIdUrlRewritingEnabled(false);
return sessionManager;
}
@Bean("sessionIdCookie")
public SimpleCookie sessionIdCookie(){
SimpleCookie simpleCookie = new SimpleCookie("sid");
simpleCookie.setHttpOnly(true);
simpleCookie.setPath("/");
//maxAge=-1表示瀏覽器關閉時失效此Cookie
simpleCookie.setMaxAge(-1);
return simpleCookie;
}
需要自己實現session監聽:
public interface SessionListener {
void onStart(Session var1);
void onStop(Session var1);
void onExpiration(Session var1);
}
記錄人數的:
public class ShiroSessionListener implements SessionListener {
/**
* 統計在線人數
* juc包下線程安全自增
*/
private final AtomicInteger sessionCount = new AtomicInteger(0);
/**
* 會話創建時觸發
* @param session
*/
@Override
public void onStart(Session session) {
//會話創建,在線人數加一
sessionCount.incrementAndGet();
}
/**
* 退出會話時觸發
* @param session
*/
@Override
public void onStop(Session session) {
//會話退出,在線人數減一
sessionCount.decrementAndGet();
}
/**
* 會話過期時觸發
* @param session
*/
@Override
public void onExpiration(Session session) {
//會話過期,在線人數減一
sessionCount.decrementAndGet();
}
/**
* 獲取在線人數使用
* @return
*/
public AtomicInteger getSessionCount() {
return sessionCount;
}
}
總結
這裏是web的session簡單用法,如果是java環境,那麼session就比較簡單了,前面都有分析到.不過現在一般都不使用session了,所以這一塊,只需要知道就好了,現在項目一般都是有app端的,集羣的,多應用共享的,就是單點登錄這樣的.所以基於傳統的session已經很難實現需求了,解決方案一般是shiro+jwt基於token方式實現.後期會講到