Spring Security 許可權管理的投票器與表決機制
今天我們們來聊一聊 Spring Security 中的表決機制與投票器。
當使用者想訪問 Spring Security 中一個受保護的資源時,使用者具備一些角色,該資源的訪問也需要一些角色,在比對使用者具備的角色和資源需要的角色時,就會用到投票器和表決機制。
當使用者想要訪問某一個資源時,投票器根據使用者的角色投出贊成或者反對票,表決方式則根據投票器的結果進行表決。
在 Spring Security 中,預設提供了三種表決機制,當然,我們也可以不用系統提供的表決機制和投票器,而是完全自己來定義,這也是可以的。
本文松哥將和大家重點介紹三種表決機制和預設的投票器。
1.投票器
先來看投票器。
在 Spring Security 中,投票器是由 AccessDecisionVoter 介面來規範的,我們來看下 AccessDecisionVoter 介面的實現:
可以看到,投票器的實現有好多種,我們可以選擇其中一種或多種投票器,也可以自定義投票器,預設的投票器是 WebExpressionVoter。
我們來看 AccessDecisionVoter 的定義:
我稍微解釋下:
- 首先一上來定義了三個常量,從常量名字中就可以看出每個常量的含義,1 表示贊成;0 表示棄權;-1 表示拒絕。
- 兩個 supports 方法用來判斷投票器是否支援當前請求。
- vote 則是具體的投票方法。在不同的實現類中實現。三個引數,authentication 表示當前登入主體;object 是一個 ilterInvocation,裡邊封裝了當前請求;attributes 表示當前所訪問的介面所需要的角色集合。
我們來分別看下幾個投票器的實現。
1.1 RoleVoter
RoleVoter 主要用來判斷當前請求是否具備該介面所需要的角色,我們來看下其 vote 方法:
這個方法的判斷邏輯很簡單,如果當前登入主體為 null,則直接返回 ACCESS_DENIED 表示拒絕訪問;否則就從當前登入主體 authentication 中抽取出角色資訊,然後和 attributes 進行對比,如果具備 attributes 中所需角色的任意一種,則返回 ACCESS_GRANTED 表示允許訪問。例如 attributes 中的角色為 [a,b,c],當前使用者具備 a,則允許訪問,不需要三種角色同時具備。
另外還有一個需要注意的地方,就是 RoleVoter 的 supports 方法,我們來看下:
可以看到,這裡涉及到了一個 rolePrefix 字首,這個字首是
ROLE_
,在 supports 方法中,只有主體角色字首是
ROLE_
,這個 supoorts 方法才會返回 true,這個投票器才會生效。
1.2 RoleHierarchyVoter
RoleHierarchyVoter 是 RoleVoter 的一個子類,在 RoleVoter 角色判斷的基礎上,引入了角色分層管理,也就是角色繼承,關於角色繼承,小夥伴們可以參考松哥之前的文章( Spring Security 中如何讓上級擁有下級的所有許可權?)。
RoleHierarchyVoter 類的 vote 方法和 RoleVoter 一致,唯一的區別在於 RoleHierarchyVoter 類重寫了 extractAuthorities 方法。
角色分層之後,需要透過 getReachableGrantedAuthorities 方法獲取實際具備的角色,具體請參考: Spring Security 中如何讓上級擁有下級的所有許可權? 一文。
1.3 WebExpressionVoter
這是一個基於表示式許可權控制的投票器,松哥後面專門花點時間和小夥伴們聊一聊基於表示式的許可權控制,這裡我們先不做過多展開,簡單看下它的 vote 方法:
如果你熟練使用 SpEL 的話,這段程式碼應該說還是很好理解的,不過根據我的經驗,實際工作中用到 SpEL 場景雖然有,但是不多,所以可能有很多小夥伴並不瞭解 SpEL 的用法,這個需要小夥伴們自行復習下,我也給大家推薦一篇還不錯的文章: https://www.cnblogs.com/larryzeal/p/5964621.html。
這裡程式碼實際上就是根據傳入的 attributes 屬性構建 weca 物件,然後根據傳入的 authentication 引數構建 ctx 物件,最後呼叫 evaluateAsBoolean 方法去判斷許可權是否匹配。
上面介紹這三個投票器是我們在實際開發中使用較多的三個。
1.4 其他
另外還有幾個比較冷門的投票器,松哥也稍微說下,小夥伴們瞭解下。
Jsr250Voter
處理 Jsr-250 許可權註解的投票器,如
@PermitAll
,
@DenyAll
等。
AuthenticatedVoter
AuthenticatedVoter 用於判斷 ConfigAttribute 上是否擁有 IS_AUTHENTICATED_FULLY、IS_AUTHENTICATED_REMEMBERED、IS_AUTHENTICATED_ANONYMOUSLY 三種角色。
IS_AUTHENTICATED_FULLY 表示當前認證使用者必須是透過使用者名稱/密碼的方式認證的,透過 RememberMe 的方式認證無效。
IS_AUTHENTICATED_REMEMBERED 表示當前登入使用者必須是透過 RememberMe 的方式完成認證的。
IS_AUTHENTICATED_ANONYMOUSLY 表示當前登入使用者必須是匿名使用者。
當專案引入 RememberMe 並且想區分不同的認證方式時,可以考慮這個投票器。
AbstractAclVoter
提供編寫域物件 ACL 選項的幫助方法,沒有繫結到任何特定的 ACL 系統。
PreInvocationAuthorizationAdviceVoter
使用 @PreFilter 和 @PreAuthorize 註解處理的許可權,透過 PreInvocationAuthorizationAdvice 來授權。
當然,如果這些投票器不能滿足需求,也可以自定義。
2.表決機制
一個請求不一定只有一個投票器,也可能有多個投票器,所以在投票器的基礎上我們還需要表決機制。
表決相關的類主要是三個:
- AffirmativeBased
- ConsensusBased
- UnanimousBased
他們的繼承關係如上圖。
三個決策器都會把專案中的所有投票器呼叫一遍,預設使用的決策器是 AffirmativeBased。
三個決策器的區別如下:
- AffirmativeBased:有一個投票器同意了,就透過。
- ConsensusBased:多數投票器同意就透過,平局的話,則看 allowIfEqualGrantedDeniedDecisions 引數的取值。
- UnanimousBased 所有投票器都同意,請求才透過。
這裡的具體判斷邏輯比較簡單,松哥就不貼原始碼了,感興趣的小夥伴可以自己看看。
3.在哪裡配置
當我們使用基於表示式的許可權控制時,像下面這樣:
那麼預設的投票器和決策器是在 AbstractInterceptUrlConfigurer#createDefaultAccessDecisionManager 方法中配置的:
這裡就可以看到預設的決策器和投票器,並且決策器 AffirmativeBased 物件建立好之後,還呼叫 postProcess 方法註冊到 Spring 容器中去了,結合松哥本系列前面的文章,大家知道,如果我們想要修改該物件就非常容易了:
這裡只是給大家一個演示,正常來說我們是不需要這樣修改的。當我們使用不同的許可權配置方式時,會有自動配置對應的投票器和決策器。或者我們手動配置投票器和決策器,如果是系統配置好的,大部分情況下並不需要我們修改。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69981976/viewspace-2721737/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Security 10:許可權管理
- spring security許可權認證Spring
- 基於Spring Security實現許可權管理系統Spring
- Spring security(五)-完美許可權管理系統(授權過程分析)Spring
- Spring Security 基於URL的許可權判斷Spring
- Spring Security實現統一登入與許可權控制Spring
- 最新版 Spring Security,該如何實現動態許可權管理?Spring
- Linux中的許可權機制Linux
- 專欄丨Spring Security系列教程之Spring Security的四種許可權控制方式Spring
- spring2 Aop與事務、許可權管理Spring
- android permission 許可權與安全機制解析(下)Android
- Spring Security + jwt 許可權系統設計,包含SQLSpringJWTSQL
- RBAC許可權---SpringBoot整合SecuritySpring Boot
- 基於Spring Security和 JWT的許可權系統設計SpringJWT
- 基於RBAC的許可權控制淺析(結合Spring Security)Spring
- 深入理解Spring Security授權機制原理Spring
- SpringBoot整合Spring security JWT實現介面許可權認證Spring BootJWT
- springBoot整合spring security實現許可權管理(單體應用版)--築基初期Spring Boot
- Security8:許可權模擬
- android 6.0許可權機制的簡單封裝(支援批量申請許可權)Android封裝
- SpringBoot與Shiro整合-許可權管理Spring Boot
- Linux賬戶與許可權管理Linux
- django開發之許可權管理(一)——許可權管理詳解(許可權管理原理以及方案)、不使用許可權框架的原始授權方式詳解Django框架
- 基於 Spring Security 的前後端分離的許可權控制系統Spring後端
- Odoo許可權管理Odoo
- 特殊許可權管理
- sql許可權管理SQL
- 許可權管理策略
- MySQL許可權管理MySql
- 4、許可權管理
- RBAC許可權管理
- PostgreSQL:許可權管理SQL
- MongoDB 使用者與許可權管理MongoDB
- Linux 中的許可權管理Linux
- Linux 下許可權的管理Linux
- fastadmin的許可權管理authAST
- 長沙Java培訓班分享:Spring教程之Spring Security的四種許可權控制方式JavaSpring
- springBoot整合spring security+JWT實現單點登入與許可權管理前後端分離--築基中期Spring BootJWT後端