做爲訪問控制的最後一期,但確實整個章節部分裏最簡單的一部分。ConfigAttribute
負責表述規則,AccessDecisionVoter
負責爲規則表決,但最終的訪問受權是否經過是由AccessDecisionManager
進行決策的。 這一期咱們將主要介紹Spring Security中提供的三種主要決策模型。java
AccessDecisionManager
的接口表述很是的簡單,簡單來講就一個主要功——爲當前的訪問規則進行決策,是否給予訪問的權限。不管是decide方法仍是supports方法,AccessDecisionManager
自己並不完成相關的邏輯,所有交由其管理的AccessDecisionVoter
依次去判斷與執行。而根據decide的邏輯規則不一樣,Spring Security中分別存在三種不一樣decide決策規則的AccessDecisionManager
,它們分別是:spring
AffirmativeBased
。
在詳細介紹三種AccessDecisionManager
的實現類前,咱們先再來梳理下AccessDecisionManager
與AccessDecisionVoter
的在決策框架中的關係。 在框架設計中AccessDecisionManager
是AccessDecisionVoter
的集合類,管理着對於不一樣規則進行判斷與表決的AccessDecisionVoter
們。 但不一樣的是,AccessDecisionVoter
分別都只會對本身支持的規則進行表決,如一個資源的訪問規則存在多個並行時,便不能以某一個AccessDecisionVoter
的表決做爲最終的訪問受權結果。AccessDecisionManager
的職責即是在這種場景下,彙總全部AccessDecisionVoter
的表決結果後給出一個最終的決策。從而致使框架中預設了三種不一樣決策規則的AccessDecisionManager
的實現類。 express
第一個咱們來介紹,Spring Security中默認提供的訪問決策模型AffirmativeBased
。一句話來講AffirmativeBased
的邏輯就是一票經過——當前只要存在任何一個投了贊同表的AccessDecisionVoter
便會最終給予相關受權。bash
affirmative adj. 確定的;積極的 n. 確定語;同意的一方app
假設存在資源A,在RoleVoter
中要求有Admin的角色,而在MinutedOddVoter
中缺只要是奇數分鐘則能夠訪問。那麼在AffirmativeBased
模型下,即時用於沒有Admin的角色,只要知足奇數分鐘的條件同樣能夠訪問目標資源。框架
@Secured({"IS_AUTHENTICATED_FULLY","ROLE_USER","MINUTE_ODD"})
@RequestMapping("/")
public String root(@Autowired Authentication authentication) {
return "index";
}
複製代碼
當咱們奇數分鐘數訪問對應資源的時候:ide
Voter: org.springframework.security.access.vote.RoleVoter@508280a4, returned: -1
Voter: org.springframework.security.access.vote.AuthenticatedVoter@2846f995, returned: -1
Voter: com.newnil.demo.security.MinuteBasedVoter@1ec9ec13, returned: 1
Authorization successful
複製代碼
即便RoleVoter
與AuthenticatedVoter
存在明確的反對,可是由於MinuteBasedVoter
知足了時間的要求,同樣會獲得一個確定的結果。 這邊有一個經驗,在默認的AffirmativeBased
的模型下客製化AccessDecisionVoter
若是不是很決定性的規則,諸如一些輔助性的訪問限制避免投出明確的贊同表,而是換個角度,投出明確的反對票,如不知足反對的狀況能夠投出棄權票。咱們在上一期客製化的MinuteBasedVoter
即是一個很差的反面教材^_^。測試
第二個,咱們再來介紹一個備選的決策規則,即UnanimousBased
所表明的一票不然制,全部人都沒有反對意見。this
unanimous adj. 全體一致的;意見一致的;無異議的spa
其規則也十分容易懂,只要任意一個AccessDecisionVoter
投出了反對票,則不管有多少個贊同票都沒法受權訪問權限。UnanimousBased
表明了與AffirmativeBased
徹底對立的規則,有點相似五常表決的一票不然制,好比前幾年著名的新聞「土耳其要求取消俄羅斯的一票否決票,這個提案被俄羅斯一票否決了」。 一樣回到代碼上來,咱們經過調整Java Config配置代碼將使用的AccessDecisionManager
實現變動爲UnanimousBased
。
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true)
@Configuration
public class MethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
@Override
protected AccessDecisionManager accessDecisionManager() {
List<AccessDecisionVoter<? extends Object>> decisionVoters = new ArrayList();
ExpressionBasedPreInvocationAdvice expressionAdvice = new ExpressionBasedPreInvocationAdvice();
expressionAdvice.setExpressionHandler(this.getExpressionHandler());
decisionVoters.add(new RoleVoter());
decisionVoters.add(new AuthenticatedVoter());
decisionVoters.add(new MinuteBasedVoter());
return new UnanimousBased(decisionVoters);
}
}
複製代碼
對於一樣的場景下,如用戶已經登陸並擁有了對應的權限而由於當前時間不是偶數分鐘,那麼最終的決策結果由於有一票否決變爲了不可訪問
Voter: org.springframework.security.access.vote.RoleVoter@ddc490, returned: 0
Voter: org.springframework.security.access.vote.AuthenticatedVoter@27f66035, returned: 1
Voter: com.newnil.demo.security.MinuteBasedVoter@4f6b68aa, returned: -1
Access is denied (user is not anonymous);
複製代碼
最後出場的ConsensusBased
多是三個規則裏最「民主」,即少數服從多數制。
consensus n. 一致;輿論;合意
ConsensusBased
對全部投票的AccessDecisionVoter
的意見進行彙總,以數量多那一方的結果爲準。 可是存在一種特殊狀況——平票:若是產平生票則根據配置allowIfEqualGrantedDeniedDecisions
來判斷是否經過,在默認狀況下allowIfEqualGrantedDeniedDecisions
值是true。
一樣的咱們修改Java Config來測試下ConsensusBased
的行爲:
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true)
@Configuration
public class MethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
@Override
protected AccessDecisionManager accessDecisionManager() {
List<AccessDecisionVoter<? extends Object>> decisionVoters = new ArrayList();
ExpressionBasedPreInvocationAdvice expressionAdvice = new ExpressionBasedPreInvocationAdvice();
expressionAdvice.setExpressionHandler(this.getExpressionHandler());
decisionVoters.add(new RoleVoter());
decisionVoters.add(new AuthenticatedVoter());
decisionVoters.add(new MinuteBasedVoter());
ConsensusBased consensusBased = new ConsensusBased(decisionVoters);
consensusBased.setAllowIfEqualGrantedDeniedDecisions(false);//能夠調整平票邏輯
return consensusBased;
}
}
複製代碼
咱們一樣在偶數分鐘訪問,在登陸後訪問受限制的資源:
Voter: org.springframework.security.access.vote.RoleVoter@2c1ae72c, returned: 1
Voter: org.springframework.security.access.vote.AuthenticatedVoter@60d5234, returned: 1
Voter: com.newnil.demo.security.MinuteBasedVoter@6a34393c, returned: -1
Authorization successful
複製代碼
與以前UnanimousBased
的表現不一樣,由於贊同票大於否對票因此咱們最終仍是獲取了訪問的權限。
做爲訪問控制的最後一個組件,因爲有了以前的鋪墊和了解,三種決策規則相比之下會顯得簡單不少。而且在一般的狀況下,對於AccessDecisionManager
咱們也不太會存在任何客製化的可能性。咱們只須要了解如何選擇合適的AccessDecisionManager
與如何編寫相關的Java配置代碼便可。 從下一期開始,咱們將進入新的主題開始介紹Spring Security中的config包下關於配置的一些內容。 咱們下期再見。