Spring Security教程 Vol 9. AccessDecisionManager組件介紹

第九期 AccessDecisionManager組件介紹

做爲訪問控制的最後一期,但確實整個章節部分裏最簡單的一部分。ConfigAttribute負責表述規則,AccessDecisionVoter負責爲規則表決,但最終的訪問受權是否經過是由AccessDecisionManager進行決策的。 這一期咱們將主要介紹Spring Security中提供的三種主要決策模型。java

1、AccessDecisionManager接口說明

AccessDecisionManager的接口表述很是的簡單,簡單來講就一個主要功——爲當前的訪問規則進行決策,是否給予訪問的權限。不管是decide方法仍是supports方法,AccessDecisionManager自己並不完成相關的邏輯,所有交由其管理的AccessDecisionVoter依次去判斷與執行。而根據decide的邏輯規則不一樣,Spring Security中分別存在三種不一樣decide決策規則的AccessDecisionManager,它們分別是:spring

  • AffirmativeBased
  • UnanimousBased
  • ConsensusBased 在Spring Security默認設置中,使用的是AffirmativeBased
    AccessDecisionManager接口

在詳細介紹三種AccessDecisionManager的實現類前,咱們先再來梳理下AccessDecisionManagerAccessDecisionVoter的在決策框架中的關係。 在框架設計中AccessDecisionManagerAccessDecisionVoter的集合類,管理着對於不一樣規則進行判斷與表決的AccessDecisionVoter們。 但不一樣的是,AccessDecisionVoter分別都只會對本身支持的規則進行表決,如一個資源的訪問規則存在多個並行時,便不能以某一個AccessDecisionVoter的表決做爲最終的訪問受權結果。AccessDecisionManager的職責即是在這種場景下,彙總全部AccessDecisionVoter的表決結果後給出一個最終的決策。從而致使框架中預設了三種不一樣決策規則的AccessDecisionManager的實現類。 express

image.png

2、一票經過AffirmativeBased

第一個咱們來介紹,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
複製代碼

即便RoleVoterAuthenticatedVoter存在明確的反對,可是由於MinuteBasedVoter知足了時間的要求,同樣會獲得一個確定的結果。 這邊有一個經驗,在默認的AffirmativeBased的模型下客製化AccessDecisionVoter若是不是很決定性的規則,諸如一些輔助性的訪問限制避免投出明確的贊同表,而是換個角度,投出明確的反對票,如不知足反對的狀況能夠投出棄權票。咱們在上一期客製化的MinuteBasedVoter即是一個很差的反面教材^_^。測試

3、一票否決UnanimousBased

第二個,咱們再來介紹一個備選的決策規則,即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);
複製代碼

4、少數服從多數ConsensusBased

最後出場的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包下關於配置的一些內容。 咱們下期再見。

相關文章
相關標籤/搜索