前言 開心一刻 開學了,表弟和同學因為打架,老師讓他回去叫家長。表弟硬氣的說:不用,我打得過他。老師板著臉對他說:和你打架的那位同學已經回去叫家長了。表弟猶豫了一會依然硬氣的說:可以,兩個我也打得過。老師:...... 路漫漫其修遠兮,吾將上下而求索! github:https://github.c ...
前言
開心一刻
開學了,表弟和同學因為打架,老師讓他回去叫家長。表弟硬氣的說:不用,我打得過他。老師板著臉對他說:和你打架的那位同學已經回去叫家長了。表弟猶豫了一會依然硬氣的說:可以,兩個我也打得過。老師:......
路漫漫其修遠兮,吾將上下而求索!
github:https://github.com/youzhibing
碼雲(gitee):https://gitee.com/youzhibing
前情回顧
大家還記得上篇博文講了什麼嗎,我們來一起簡單回顧下:
HttpServletRequestWrapper是HttpServletRequest的裝飾類,我們通過繼承HttpServletRequestWrapper來實現我們自定義的HttpServletRequest:CustomizeSessionHttpServletRequest,重寫CustomizeSessionHttpServletRequest的getSession,將其指向我們自定義的session。然後通過Filter將CustomizeSessionHttpServletRequest添加到Filter chain中,使得到達Servlet的ServletRequest是我們的CustomizeSessionHttpServletRequest。
今天不講session共用,我們先來看看shiro的session管理
SecurityManager
SecurityManager,安全管理器;即所有與安全相關的操作都會與SecurityManager交互;它管理著所有Subject,所有Subject都綁定到SecurityManager,與Subject的所有交互都會委托給SecurityManager;SecurityManager是shiro的核心,它負責與shiro的其他組件進行交互,類似SpringMVC中的DispatcherServlet或Struts2中的FilterDispatcher。
我們在使用shiro的時候,首先都會先初始化SecurityManager,然後往SecurityManager中註入shiro的其他組件,像sessionManager、realm等。我們的spring-boot-shiro中初始化的是DefaultWebSecurityManager,如下
@Bean public SecurityManager securityManager(AuthorizingRealm myShiroRealm, CacheManager shiroRedisCacheManager) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setCacheManager(shiroRedisCacheManager); securityManager.setRememberMeManager(cookieRememberMeManager()); securityManager.setRealm(myShiroRealm); return securityManager; }View Code
SecurityManager類圖
結構如下,認真看看,註意看下屬性
頂層組件SecurityManager直接繼承了SessionManager且提供了SessionsSecurityManager實現,SessionsSecurityManager直接把會話管理委托給相應的SessionManager;SecurityManager的預設實現:DefaultSecurityManager及DefaultWebSecurityManager都繼承了SessionsSecurityManager,也就是說:預設情況下,session的管理由DefaultSecurityManager或DefaultWebSecurityManager中的SessionManager來負責。
DefaultSecurityManager
預設安全管理器,用於我們的javaSE安全管理,一般而言用到的少,但我們需要記住,萬一哪次有這個需求呢。
我們來看下他的構造方法
預設的sessionManager是DefaultSessionManager,DefaultSessionManager具體詳情請看下文。
DefaultWebSecurityManager
預設web安全管理器,用於我們的web安全管理;一般而言,我們的應用中初始化此安全管理器。
我們來看看其構造方法
public DefaultWebSecurityManager() { super(); // 會調用SessionsSecurityManager的構造方法,實例化DefaultSessionManager ((DefaultSubjectDAO) this.subjectDAO).setSessionStorageEvaluator(new DefaultWebSessionStorageEvaluator()); this.sessionMode = HTTP_SESSION_MODE; setSubjectFactory(new DefaultWebSubjectFactory()); setRememberMeManager(new CookieRememberMeManager()); setSessionManager(new ServletContainerSessionManager()); // 設置sessionManager,替換掉上面的DefaultSessionManager }View Code
可以看出此時的sessionManager是ServletContainerSessionManager,ServletContainerSessionManager具體詳情請看下文。
由此可知預設情況下,DefaultSecurityManager會將session管理委托給DefaultSessionManager,而DefaultWebSecurityManager則將session管理委托給ServletContainerSessionManager。
我們可以通過繼承DefaultSecurityManager或DefaultWebSecurityManager來實現自定義SecurityManager,但一般而言沒必要,DefaultSecurityManager和DefaultWebSecurityManager基本能滿足我們的需要了,我們根據需求二選其一即可。無論DefaultSecurityManager還是DefaultWebSecurityManager,我們都可以通過setSessionManager方法來指定sessionManager,如果不指定sessionManager的話就用的SecurityManager預設的sessionManager。
SessionManager
shiro提供了完整的會話管理功能,不依賴底層容器,JavaSE應用和JavaEE應用都可以使用。會話管理器管理著應用中所有Subject的會話,包括會話的創建、維護、刪除、失效、驗證等工作。
SessionManager類圖
DefaultSessionManager
DefaultSecurityManager預設使用的SessionManager,用於JavaSE環境的session管理。
通過上圖可知(結合SecurityManager類圖),session創建的關鍵入口是SessionsSecurityManager的start方法,此方法中會將session的創建任務委托給具體的SessionManager實現。
DefaultSessionManager繼承自AbstractNativeSessionManager,沒用重寫start方法,所以此時AbstractNativeSessionManager的start方法會被調用,一路往下跟,最終會調用DefaultSessionManager的doCreateSession方法完成session的創建,doCreateSession方法大家可以自行去跟下,我在這總結一下:
創建session,並生成sessionId,session是shiro的SimpleSession類型,sessionId採用的是隨機的UUID字元串;
sessionDAO類型是MemorySessionDAO,session存放在sessionDAO的private ConcurrentMap<Serializable, Session> sessions;屬性中,key是sessionId,value是session對象;
除了MemorySessionDAO,shiro還提供了EnterpriseCacheSessionDAO,具體兩者有啥區別請看我的另一篇博客講解。
ServletContainerSessionManager
DefaultWebSecurityManager預設使用的SessionManager,用於Web環境,直接使用的Servlet容器的會話,具體實現我們往下看。
ServletContainerSessionManager實現了SessionManager,並重寫了SessionManager的start方法,那麼我們從ServletContainerSessionManager的start方法開始來看看session的創建過程,如下圖
shiro有自己的HttpServletSession,HttpServletSession持有servlet的HttpSession的引用,最終對HttpServletSession的操作都會委托給HttpSession(裝飾模式)。那麼此時的session是標準servlet容器支持的HttpSession實例,它不與Shiro的任何與會話相關的組件(如SessionManager,SecurityManager等)交互,完全由servlet容器管理。
DefaultWebSessionManager
用於Web環境,可以替換ServletContainerSessionManager,廢棄了Servlet容器的會話管理;通過此可以實現我們自己的session管理;
從SessionManager類圖可知,DefaultWebSessionManager繼承自DefaultSessionManager,也沒有重寫start方法,那麼創建過程還是沿用的AbstractNativeSessionManager的start方法;如果我們沒有指定自己的sessionDao,那麼session還是存在MemorySessionDAO的ConcurrentMap<Serializable, Session> sessions中,具體可以看上述中的DefaultSessionManager。
通過DefaultWebSessionManager實現session共用,盡請期待!
總結
兩個類圖
SecurityManager和SessionManager的類圖需要認真看看;
Subject的所有交互都會委托給SecurityManager;SecurityManager是shiro的核心,它負責與shiro的其他組件進行交互,類似SpringMVC中的DispatcherServlet或Struts2中的FilterDispatcher;
SecurityManager會將session管理委托給SessionManager;SessionsSecurityManager的start方法中將session的創建委托給了具體的sessionManager,是創建session的關鍵入口。
shiro的SimpleSession與HttpServletSession
HttpServletSession只是servlet容器的session的裝飾,最終還是依賴servlet容器,是shiro對servlet容器的session的一種支持;
而SimpleSession是shiro完完全全的自己實現,是shiro對session的一種拓展。
參考
《跟我學shiro》