這篇博客就來寫一寫之前學習shiro框架整合的時候,產生的一些問題,相信大家在學習的時候也有相應的一些疑惑。接下來就針對shiro中的session和cookie來捋一捋。
shiro整合學習的總結
-
shiro+redis集成,避免每次訪問有權限的鏈接都會去執行MyShiroRealm.doGetAuthenticationInfo()方法來查詢當前用戶的權限,因爲實際情況中權限是不會經常變得,這樣就可以使用redis進行權限的緩存。
-
實現shiro鏈接權限的動態加載,之前要添加一個鏈接的權限,要在shiro的配置文件中添加filterChainDefinitionMap.put(“/add”, “roles[100002],perms[權限添加]”),這樣很不方便管理,一種方法是將鏈接的權限使用數據庫進行加載,另一種是通過init配置文件的方式讀取。
-
Shiro 自定義權限校驗Filter定義,及功能實現。
-
Shiro Ajax請求權限不滿足,攔截後解決方案。這裏有一個前提,我們知道Ajax不能做頁面redirect和forward跳轉,所以Ajax請求假如沒登錄,那麼這個請求給用戶的感覺就是沒有任何反應,而用戶又不知道用戶已經退出了。
-
控制同一個用戶的在線數量。(擠出之前的登錄用戶)
-
Shiro 登錄後跳轉到最後一個訪問的頁面
-
在線顯示,在線用戶管理(踢出登錄)。
-
登錄註冊密碼加密傳輸。
-
集成動態驗證碼。
-
記住我的功能。關閉瀏覽器後還是登錄狀態。
·······················································································································································
此項目下載地址:https://git.oschina.net/z77z/springboot_mybatisplus
·······················································································································································
session
session是大家比較熟悉的功能,因爲HTTP協議是無狀態的,網站爲了在多個請求之間傳遞數據就使用了session這個東西,session是存儲在網站服務器上的某個地方,比如內存、數據庫或者其他的什麼東西,在我的配置中是用redis存儲的,因爲我使用了Shiro的Native Session Manager,替代了Tomcat本身的Session Manager,並且爲Shiro的Native Session Manager配置了redis的SessionDAO,當然這個我是直接使用的一個開源插件,裏面已經幫我們很好的實現了cacheManager,sessionManager,redisSessionDAO這些。直接使用就可以了。
shiro_redis插件地址:http://www.oschina.net/p/shiro-redis
所以所有的session會話都是緩存在redis裏面的。對session的增刪改查都是在操作redis數據庫來完成。所以如果將redis進行集羣的話,session會話也就會達到集羣的目的。後面我專門寫博客來分享。
在這種情況下服務器的Session就存儲在redis裏面,如果某個Session過期(比如關閉了瀏覽器或者超時),此條Session就會從redis裏面永久刪除,下次的請求將不能使用Session裏面的數據。所以說即使有些url設置的是”user”級別的(也就是說不用登錄即可訪問,只須設置了rememberMe),但是如果這些url使用了Session裏面的數據,就會拋出異常,因爲此時這個用戶對應的Session已經不存在了。
cookie
當瀏覽一個網站的時候,網站返回給你一個Session Cookie和一個RememberMe Cookie,Session Cookie很好理解,就是爲了此次的對話,一旦關閉了瀏覽器或者超時了Session Cookie就沒用了。但是RememberMe Cookie不太一樣,Shiro默認的RememberMe Cookie的時長是一年,所以不用擔心這個Cookie的情況。RememberMe Cookie實際就是Shiro把這個用戶的信息加密一下放到cookie裏面,下次就可以根據這個cookie來進行判斷這是哪個用戶。
主要講下shiro的rememberMe cookie。在shiro中有一個類實現了rememberMe功能, org.apache.shiro.web.mgt.CookieRememberMeManager 。在登錄時,代碼也很簡單:
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
token.setRememberMe(true);
subject.login(token);
RememberMe這個參數設置爲true後,在登陸的時候就會在客戶端設置remenberme的相應cookie。下次訪問帶上這個cookie,訪問鏈接爲user鏈接器的,就不需要進行登錄驗證,直接進入權限驗證。下面是完整的處理過程:
- 得到principals對象
- 通過配置的key,使用aes加密
- 將加密後的值再通過base64解密
- 當客戶端帶着這個rememberMe cookie訪問時,將會按照下面的過程來尋找已記住的身份信息:
- 獲取rememberMe cookie的值
- Base64解碼
- 使用AES解密
- 使用ObjectInputStream進行反序列化
這樣不需要進入身份驗證的攔截器,就直接從cookie中獲取到了登錄信息。
未解決疑惑
session整個流程很好理解,我們使用的插件,對session的操作理解可以去看我之前寫的在線用戶管理和控制在線人數功能,基本都是對session的操作。
https://my.oschina.net/z707z/blog/852189
對於cookie我又下面幾點疑惑,忘大神指點:
-
我在測試的時候,使用了remenberme的功能後,我將登錄生成的cookie複製出來,我不管重新登錄相同用戶多少次,我帶上這個cookie訪問的時候,還是不會走身份驗證這個攔截器。只走權限驗證的攔截器,也就是說用戶在使用退出登錄後。之前的cookie還是有效的。並沒有清除。怎麼清除cookie。不是所清除客戶端的cookie,而是清除服務器記住的cookie序列化文件。
-
有沒有什麼好的方法可以防止盜取cookie,進行xss攻擊。
網上找了一個思路:
- 用戶選擇了 “記住我” 成功登錄後,將會把 username、隨機產生的序列號、生成的 token 存入一個數據庫表中,同時將它們的組合生成一個 cookie 發送給客戶端瀏覽器。
- 當下一次沒有登錄的用戶訪問系統時,首先檢查 cookie,如果對應 cookie 中包含的 username、序列號和 token 與數據庫中保存的一致,則表示其通過驗證,系統將重新生成一個新的 token 替換數據庫中對應組合的舊 token,序列號保持不變,同時刪除舊的 cookie,重新生成包含新生成的 token,就的序列號和 username 的 cookie 發送給客戶端。
- 如果檢查 cookie 時,cookie 中包含的 username 和序列號跟數據庫中保存的匹配,但是 token 不匹配。這種情況極有可能是因爲你的 cookie 被人盜用了,由於盜用者使用你原本通過認證的 cookie 進行登錄了導致舊的 token 失效,而產生了新的 token。這個時候 shiro就可以發現 cookie 被盜用的情況,它將刪除數據庫中與當前用戶相關的所有 token 記錄,這樣盜用者使用原有的 cookie 將不能再登錄,同時提醒用戶其帳號有被盜用的可能性。
- 如果對應 cookie 不存在,或者包含的 username 和序列號與數據庫中保存的不一致,那麼將會引導用戶到登錄頁面。
這樣處理有一個不好的地方就是:必須要每次用戶要再次操作的時候纔會發現cookie被盜用,如果被盜用的cookie是用戶最後一次操作生成的cookie吶。
我到覺得控制用戶登錄人數爲只能一個人登錄一個帳號,還比上面這個方便些,不會反覆的生成cookie,寫入cookie。但是也不好,沒有解決服務器上的cookie沒有根據用戶的退出而失效的這個問題。