摘要
shiro 的會話管理基本都寫好了捺檬,可以直接用它默認的再层,也可以關閉它的會話用自己的。這很開放堡纬,當然我肯定不會自己寫聂受,直接用它的,有個別需求的還可以實現(xiàn)它的接口自己寫烤镐,對著它的實現(xiàn)去修改蛋济,也不是很難。
項目地址:https://github.com/thecattle/spring-mvc-shiro
下面主要從兩方面說一下炮叶。
- session 管理
- cookie 管理(記住我-rememberMe)
session
在 shiro.xml 中碗旅,如下 我僅僅是設置超時時間為40分鐘渡处,默認30分鐘。
- globalSessionTimeout:全局 session 過期時間祟辟,單位是 毫秒
- cache:對于 session 管理可以配置 cache医瘫,可以集成 ehcache,redis 等旧困。不設置默認使用內(nèi)存作為緩存醇份。
- sessionDao: 主要實現(xiàn) session 的增刪改查,有個性化需求可以自己實現(xiàn)吼具,在此不多啰嗦僚纷,有需要可以自己去看DefaultWebSessionManager。
說到DefaultWebSessionManager這個類拗盒,sessionManager的實現(xiàn)類大概有兩個:
- DefaultWebSessionManager:它支持 web 容器的 session 管理怖竭,可以滿足大多數(shù)應用。如果不配置 session 管理陡蝇,默認就是這貨侵状。
- ServletContainerSessionManager:它只支持Servlet容器的 session 管理,web 的 session 都管理不了毅整,特定需求下可以用這個趣兄。具體的可以看這個實現(xiàn)類的說明,英文我怕翻譯出歧義悼嫉。艇潭。。
<!--session管理 配置-->
<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<!--session 過期時間 單位 毫秒戏蔑,2400000=40min-->
<property name="globalSessionTimeout" value="2400000"></property>
<!--有需要可以自行配置-->
<!--<property name="cacheManager" ref="xxxx"></property>-->
<!--有需要可以自行配置-->
<!--<property name="sessionDAO" ref="xxx"></property>-->
</bean>
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
......
<!--配置 session 管理-->
<property name="sessionManager" ref="sessionManager"></property>
</property>
......
</bean>
<bean id="shiroFilter" class="com.sunp.shiro.MyShiroFilterFactoryBean">
<!-- Shiro的核心安全接口蹋凝,這個屬性是必須的 -->
<property name="securityManager" ref="securityManager"/>
......
</bean>
rememberMe
在登錄的時候可以看到這句代碼:
說實話這功能看起來挺屌的,知道原理后感覺好 low总棵,但整體來說還是很實用的鳍寂。
這東西到底是干嘛的呢。引用官方的解釋:
假設您正在使用Amazon.com情龄。您已成功登錄迄汛,并已將幾本圖書添加到購物車。但是你必須跑出一個會議骤视,但忘記注銷鞍爱。在會議結束的時候,現(xiàn)在是回家专酗,離開辦公室的時候了睹逃。
第二天,當你上班祷肯,你意識到你沒有完成你的購買沉填,所以你回到amazon.com疗隶。這一次,亞馬遜記得“你是誰”翼闹,通過名字來迎接你斑鼻,還給你一些個性化的書籍推薦。進入亞馬遜橄碾,subject.isRemembered()會返回 true卵沉。但是颠锉,如果您嘗試訪問您的帳戶以更新信用卡信息以使您的圖書購買法牲,會發(fā)生什么?
雖然亞馬遜記得你(isRemembered()== true)琼掠,但不能保證你實際上是你(例如拒垃,也許同事使用你的電腦)。因此瓷蛙,在您執(zhí)行敏感操作(如更新信用卡信息)之前悼瓮,亞馬遜將強制您登錄,以確保您的身份艰猬。登錄后横堡,您的身份已經(jīng)通過驗證,isAuthenticated()是true冠桃。對于許多類型的應用程序命贴,這種情況發(fā)生得如此頻繁,因此功能內(nèi)置于Shiro食听,因此您可以將其用于自己的應用程序⌒刂耄現(xiàn)在,無論您使用isRemembered()還是isAuthenticated()
自定義您的視圖和工作流程都取決于您樱报,但是葬项,如果您需要,Shiro將保持此基本狀態(tài)迹蛤。
看完這個故事民珍,應該能猜到,isAuthenticated為 true 說明我在登錄狀態(tài)盗飒,isRemembered為 true 說明我登錄過穷缤,就是這么簡單。難怪我上某寶的時候經(jīng)陈崾蓿看到自己是在線的津肛,下單的時候卻還要我登錄。我心里無數(shù)次罵過這網(wǎng)站是不是有病汗贫,老子在線呢你還要我登錄身坐,麻不麻煩秸脱,現(xiàn)在看到這個才恍然大悟阳掐,很慚愧擒悬,虧我還是碼農(nóng)。跑題了狐胎,說正事
作為碼農(nóng)了解到它的用處之后涯鲁,而且還這么簡單就一句代碼巷查,肯定是要看下效果的。
但是都不知道怎么實現(xiàn)的抹腿,都不知道怎么樣看到效果岛请,我去網(wǎng)上查了很久,沒查到警绩。想到是不是 session 過期了就行呢崇败,嘗試了下果然成功了。猜到結果是isRemembered是根據(jù) cookie 過沒過期來判斷的肩祥。后來配置 cookie 過期時間的時候發(fā)現(xiàn)果然是這樣后室。但我還是不知道,怎么通過源碼去知道是通過 cookie過期時間判斷混狠,大神可以指點下我岸霹,小弟感激不盡。
說說remember的 cookie 的配置:
在 DefaultWebSecurityManager 中注入CookieRememberMeManager這個實現(xiàn)類
CookieRememberMeManager中的參數(shù)是 cookie将饺,用SimpleCookie這個實現(xiàn)類
- maxAge:cookie 的超時時間贡避,單位是 秒
- SimpleCookie構造函數(shù):要傳入這個 cookie 的名字,默認有個名字
<!--rememberMeManager管理 配置-->
<bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
<property name="cookie">
<bean class="org.apache.shiro.web.servlet.SimpleCookie">
<!--設置超時時間 單位 秒俯逾,一天=86400-->
<constructor-arg value="shiro-cookie"></constructor-arg>
<property name="maxAge" value="86400"></property>
</bean>
</property>
</bean>
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
......
<!--配置 記住我-->
<property name="rememberMeManager" ref="rememberMeManager"></property>
......
</bean>
<bean id="shiroFilter" class="com.sunp.shiro.MyShiroFilterFactoryBean">
<!-- Shiro的核心安全接口贸桶,這個屬性是必須的 -->
<property name="securityManager" ref="securityManager"/>
......
</bean>
認證和記住兩個狀態(tài)的區(qū)分
說了這么多也都理解了,但是在代碼中有個問題是要注意的:
currentUser.isRemembered()和currentUser.isAuthenticated()這個兩個狀態(tài)永遠永遠都是相反的桌肴。一個為 true 一個必定為 false皇筛。除非你去重寫他們的方法。
shiro 這么做是有道理的坠七。
你是認證狀態(tài)的時候水醋,去做認證的能做事情。
你是認證記住我的時候彪置,去做記住我能做的事情拄踪。
這屬于兩個權限級別。
測試
通過設置 session 和 cookie 的超時時間拳魁,去做這個測試:
session 設置10分鐘
cookie 設置20分鐘
通過接口可以看到一開始是這樣的:
currentUser.isAuthenticated()返回 true
currentUser.isRemembered()返回 false
超過10分鐘之后
currentUser.isAuthenticated()返回 false
currentUser.isRemembered()返回 true
在此不上截圖惶桐,可以自己去測試