shiro的session管理

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方式實現.後期會講到

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章