這篇文章主要講解了“Spring Security權限管理的投票器與表決機制怎么實現(xiàn)”,文中的講解內(nèi)容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Spring Security權限管理的投票器與表決機制怎么實現(xiàn)”吧!
成都創(chuàng)新互聯(lián)公司成立與2013年,先為赤城等服務建站,赤城等地企業(yè),進行企業(yè)商務咨詢服務。為赤城企業(yè)網(wǎng)站制作PC+手機+微官網(wǎng)三網(wǎng)同步一站式服務解決您的所有建站問題。
先來看投票器。
在 Spring Security 中,投票器是由 AccessDecisionVoter 接口來規(guī)范的,我們來看下 AccessDecisionVoter 接口的實現(xiàn):
可以看到,投票器的實現(xiàn)有好多種,我們可以選擇其中一種或多種投票器,也可以自定義投票器,默認的投票器是 WebExpressionVoter。
我們來看 AccessDecisionVoter 的定義:
public interface AccessDecisionVoter<s> { int ACCESS_GRANTED = 1; int ACCESS_ABSTAIN = 0; int ACCESS_DENIED = -1; boolean supports(ConfigAttribute attribute); boolean supports(Class<!--?--> clazz); int vote(Authentication authentication, S object, Collection<configattribute> attributes); }
我稍微解釋下:
首先一上來定義了三個常量,從常量名字中就可以看出每個常量的含義,1 表示贊成;0 表示棄權;-1 表示拒絕。
兩個 supports 方法用來判斷投票器是否支持當前請求。
vote 則是具體的投票方法。在不同的實現(xiàn)類中實現(xiàn)。三個參數(shù),authentication 表示當前登錄主體;object 是一個 ilterInvocation,里邊封裝了當前請求;attributes 表示當前所訪問的接口所需要的角色集合。
我們來分別看下幾個投票器的實現(xiàn)。
RoleVoter 主要用來判斷當前請求是否具備該接口所需要的角色,我們來看下其 vote 方法:
public int vote(Authentication authentication, Object object, Collection<configattribute> attributes) { if (authentication == null) { return ACCESS_DENIED; } int result = ACCESS_ABSTAIN; Collection<!--? extends GrantedAuthority--> authorities = extractAuthorities(authentication); for (ConfigAttribute attribute : attributes) { if (this.supports(attribute)) { result = ACCESS_DENIED; for (GrantedAuthority authority : authorities) { if (attribute.getAttribute().equals(authority.getAuthority())) { return ACCESS_GRANTED; } } } } return result; }
這個方法的判斷邏輯很簡單,如果當前登錄主體為 null,則直接返回 ACCESS_DENIED 表示拒絕訪問;否則就從當前登錄主體 authentication 中抽取出角色信息,然后和 attributes 進行對比,如果具備 attributes 中所需角色的任意一種,則返回 ACCESS_GRANTED 表示允許訪問。例如 attributes 中的角色為 [a,b,c],當前用戶具備 a,則允許訪問,不需要三種角色同時具備。
另外還有一個需要注意的地方,就是 RoleVoter 的 supports 方法,我們來看下:
public class RoleVoter implements AccessDecisionVoter<object> { private String rolePrefix = "ROLE_"; public String getRolePrefix() { return rolePrefix; } public void setRolePrefix(String rolePrefix) { this.rolePrefix = rolePrefix; } public boolean supports(ConfigAttribute attribute) { if ((attribute.getAttribute() != null) && attribute.getAttribute().startsWith(getRolePrefix())) { return true; } else { return false; } } public boolean supports(Class<!--?--> clazz) { return true; } }
可以看到,這里涉及到了一個 rolePrefix 前綴,這個前綴是 ROLE_
,在 supports 方法中,只有主體角色前綴是 ROLE_
,這個 supoorts 方法才會返回 true,這個投票器才會生效。
RoleHierarchyVoter 是 RoleVoter 的一個子類,在 RoleVoter 角色判斷的基礎上,引入了角色分層管理,也就是角色繼承,關于角色繼承,小伙伴們可以參考松哥之前的文章(Spring Security 中如何讓上級擁有下級的所有權限?)。
RoleHierarchyVoter 類的 vote 方法和 RoleVoter 一致,唯一的區(qū)別在于 RoleHierarchyVoter 類重寫了 extractAuthorities 方法。
@Override Collection<!--? extends GrantedAuthority--> extractAuthorities( Authentication authentication) { return roleHierarchy.getReachableGrantedAuthorities(authentication .getAuthorities()); }
角色分層之后,需要通過 getReachableGrantedAuthorities 方法獲取實際具備的角色
這是一個基于表達式權限控制的投票器,松哥后面專門花點時間和小伙伴們聊一聊基于表達式的權限控制,這里我們先不做過多展開,簡單看下它的 vote 方法:
public int vote(Authentication authentication, FilterInvocation fi, Collection<configattribute> attributes) { assert authentication != null; assert fi != null; assert attributes != null; WebExpressionConfigAttribute weca = findConfigAttribute(attributes); if (weca == null) { return ACCESS_ABSTAIN; } EvaluationContext ctx = expressionHandler.createEvaluationContext(authentication, fi); ctx = weca.postProcess(ctx, fi); return ExpressionUtils.evaluateAsBoolean(weca.getAuthorizeExpression(), ctx) ? ACCESS_GRANTED : ACCESS_DENIED; }
這里代碼實際上就是根據(jù)傳入的 attributes 屬性構建 weca 對象,然后根據(jù)傳入的 authentication 參數(shù)構建 ctx 對象,最后調(diào)用 evaluateAsBoolean 方法去判斷權限是否匹配。
上面介紹這三個投票器是我們在實際開發(fā)中使用較多的三個。
另外還有幾個比較冷門的投票器,松哥也稍微說下,小伙伴們了解下。
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 并且想?yún)^(qū)分不同的認證方式時,可以考慮這個投票器。
AbstractAclVoter
提供編寫域?qū)ο?ACL 選項的幫助方法,沒有綁定到任何特定的 ACL 系統(tǒng)。
PreInvocationAuthorizationAdviceVoter
使用 @PreFilter 和 @PreAuthorize 注解處理的權限,通過 PreInvocationAuthorizationAdvice 來授權。
當然,如果這些投票器不能滿足需求,也可以自定義。
一個請求不一定只有一個投票器,也可能有多個投票器,所以在投票器的基礎上我們還需要表決機制。
表決相關的類主要是三個:
AffirmativeBased
ConsensusBased
UnanimousBased
他們的繼承關系如上圖。
三個決策器都會把項目中的所有投票器調(diào)用一遍,默認使用的決策器是 AffirmativeBased。
三個決策器的區(qū)別如下:
AffirmativeBased:有一個投票器同意了,就通過。
ConsensusBased:多數(shù)投票器同意就通過,平局的話,則看 allowIfEqualGrantedDeniedDecisions 參數(shù)的取值。
UnanimousBased 所有投票器都同意,請求才通過。
這里的具體判斷邏輯比較簡單,松哥就不貼源碼了,感興趣的小伙伴可以自己看看。
當我們使用基于表達式的權限控制時,像下面這樣:
http.authorizeRequests() .antMatchers("/admin/**").hasRole("admin") .antMatchers("/user/**").hasRole("user") .anyRequest().fullyAuthenticated()
那么默認的投票器和決策器是在 AbstractInterceptUrlConfigurer#createDefaultAccessDecisionManager 方法中配置的:
private AccessDecisionManager createDefaultAccessDecisionManager(H http) { AffirmativeBased result = new AffirmativeBased(getDecisionVoters(http)); return postProcess(result); } List<accessdecisionvoter<?>> getDecisionVoters(H http) { List<accessdecisionvoter<?>> decisionVoters = new ArrayList<>(); WebExpressionVoter expressionVoter = new WebExpressionVoter(); expressionVoter.setExpressionHandler(getExpressionHandler(http)); decisionVoters.add(expressionVoter); return decisionVoters; }
這里就可以看到默認的決策器和投票器,并且決策器 AffirmativeBased 對象創(chuàng)建好之后,還調(diào)用 postProcess 方法注冊到 Spring 容器中去了,結合松哥本系列前面的文章,大家知道,如果我們想要修改該對象就非常容易了:
http.authorizeRequests() .antMatchers("/admin/**").hasRole("admin") .antMatchers("/user/**").hasRole("user") .anyRequest().fullyAuthenticated() .withObjectPostProcessor(new ObjectPostProcessor<affirmativebased>() { @Override public <o extends affirmativebased> O postProcess(O object) { List<accessdecisionvoter<?>> decisionVoters = new ArrayList<>(); decisionVoters.add(new RoleHierarchyVoter(roleHierarchy())); AffirmativeBased affirmativeBased = new AffirmativeBased(decisionVoters); return (O) affirmativeBased; } }) .and() .csrf() .disable();
這里只是給大家一個演示,正常來說我們是不需要這樣修改的。當我們使用不同的權限配置方式時,會有自動配置對應的投票器和決策器。或者我們手動配置投票器和決策器,如果是系統(tǒng)配置好的,大部分情況下并不需要我們修改。
感謝各位的閱讀,以上就是“Spring Security權限管理的投票器與表決機制怎么實現(xiàn)”的內(nèi)容了,經(jīng)過本文的學習后,相信大家對Spring Security權限管理的投票器與表決機制怎么實現(xiàn)這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關知識點的文章,歡迎關注!
網(wǎng)站題目:SpringSecurity權限管理的投票器與表決機制怎么實現(xiàn)
文章來源:http://www.chinadenli.net/article38/gecopp.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供關鍵詞優(yōu)化、移動網(wǎng)站建設、用戶體驗、網(wǎng)站設計、營銷型網(wǎng)站建設、搜索引擎優(yōu)化
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)