深度剖析spring+shiro認證機制

引言

項目中使用了shiro作爲用戶認證、角色管理、權限管理等,使用起來還是特別方便的,開發者只需要SecurityUtils.getSubject()獲取subject就可以實現登錄,以及權限驗證。這樣大大簡化了開發者的功能,但是也有點讓開發者感覺好奇,shiro是如何做到的呢。

本章將會對shiro的認證機制進行深入剖析,由於從官方文檔以及其他的一些博客對shiro的使用都做了詳細的說明,所以具體的shiro的使用就不在做累述。從官網可以瞭解到,在使用shiro的時候開發者只需要和subject交互就可以實現登錄,以及相關的驗證過濾了,那麼shiro底層需要如何實現才能滿足這種需求呢,本節將對subject驗證的過程進行深入剖析。

SecurityUtils深度分析

從shiro的實用案例中,我們可以看出開發者只需要通過SecurityUtils.getSubject()方法獲取到subject,然後通過subject就可以實現用戶的login、logout、isAuthenticated等功能,那麼不同的請求時調用的SecurityUtils.getSubject()是如何保證獲取到是請求對應的用戶呢?這就需要我們對subject的來源進行一個詳細的分析!

首先通過分析SecurityUtils.getSubject()發現,該函數從線程的ThreadLocal<Map>中獲取到的subject,這個說明subject來自於web的處理線程,而且對於的key是一個常量值,但是在web服務器中一個線程可能會在不同時刻處理不同的用戶,那麼在使用同一個key的時候如何保證獲取的是當前請求的用戶的subject呢?

通過結合web服務器的線程模型、session機制,整理出了spring中shiro的一個認證的流程,大致處理過程如下,各個機制的介紹後面會進行詳細的分析:

AbstractShiroFilter的doFilterInternal方法:會爲每一個request創建一個subject(粗略的步驟是:首先提取session,然後判斷session中是否存在,如果存在那麼從session中提取用戶登錄信息放入到新建的subject),並把該subject放入當前線程的ThreadLocal<Map>中。然後當前線程繼續調用其他的filter,最後調用應用層的rest接口函數,然後rest接口函數就可以通過SecurityUtils.getSubject()方法從當前線程中的ThreadLocal<Map>中獲取subject了。

具體實現可以參考:
DefaultSubjectContext: resolvePrincipals()
AbstractShiroFilter:doFilterInternal()

session機制

由於http是無狀態的,所以在web項目中大多使用session來標識一個客戶端,shiro和web的集成也是建立在該機制之上的。

1、當服務器接受到客戶端請求的時候,首先會查找cookie是否存在,如果存在那麼繼續判斷cookie中是否存在sessionId參數;如果不存在那麼會分析url中是否有sessionId參數;如果有再判斷用戶session是否超時,如果都不存在或者是超時,那麼會重新創建一個session並把sessionId寫入response中,並返回給客戶端。

2、客戶端在收到response之後會判斷客戶端是否支持cookie機制,如果不支持那麼客戶端應該將sessionId存放在客戶端的緩存中,每一個請求都作爲url的參數放在url中。

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