前言
從這期開始我們將主要對Spring Security的另一個領域Authority,通常被稱為訪問控制的部分進行說明。 相比較Authentication身份驗證而言,客製化訪問控制的可能性相對會低許多。所以我們對這部分主要是理解流程和分析設計上的一些動機為主。 管理訪問控制對大多數讀者來說都都不太陌生,Spring Security基於角色管理的訪問控制學習起來也會較身份驗證來的又有代入感。
第六期 初識訪問控制
- 訪問控制的概述
- 訪問控制中主要的元件及實現介紹
一、關於整體結構
在之前的分享中,我們已經瞭解了在Spring Security中,對於訪問的身份驗證是通過WebFilter作為入口。然後呼叫AuthenticationManager
暴露的驗證服務介面進行驗證的。
同樣的,在驗證身份之後,如訪問受限資源,同樣也會如果身份驗證一樣,被某個WebFilter作為入口。然後呼叫一個名為AccessDecisionManager
的訪問控制決策管理器進行驗證。
在Spring Security中,主要關於訪問控制的程式碼都被放在了org.springframework.security.access.vote
包中,其中主要的介面分為三種:
AccessDecisionManager
: 負責整個訪問控制授權部分的投票策略和管理;AccessDecisionVoter
: 負責對訪問控制的規則進行表決,是否授權使用者訪問目標資源;ConfigAttribute
: 用於儲存相關的訪問控制規則
用一句話描述他們的責任就是:AccessDecisionVoter
負責對ConfigAttribute
進行表決,AccessDecsionManager
彙總表決,最終向框架返回最終的授權結果。
二、ConfigAttribute元件介紹
在一開始,我們先來回顧下,最早的應用中,我們是如何進行訪問控制的:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/user").hasRole("USER")
.antMatchers("/user").denyAll()
.and()
.formLogin();
}
複製程式碼
我們通過在configure方法中編寫路徑模式和相應的限定規則來配置整個應用的訪問控制,基於Web表示式的訪問控制規則,除了支援Spring Security中預設提供的一些限制方法以外,也可以額通過.antMatchers("/user").access("hasRole('USER') or hasRole('ADMIN')")
的access方法加上表示式的形式進行擴充套件。表示式更是可以將表達判斷委託給一個Java Class去完成。
比如下方示例程式碼就是講表示式的判斷委託給了名為webSecurity的Bean中的check方法去完成。
http
.authorizeRequests()
.antMatchers("/user/**").access("@webSecurity.check(authentication,request)")
...
複製程式碼
除了Web表示式以外,Spring Security還提供了幾種進行訪問控制配置的方式,其中最主要的一種便是通過註解在方法級對Controller和Service的方法進行對應的訪問控制的設定。
其中Spring Security對應方法級的註解主要又可以分為兩類:
第一類 @Secured
註解 - secured-annotations
第二類 @PreAuthorize, @PreFilter, @PostAuthorize and @PostFilter
- pre-post-annotations
而在Spring Security中以上兩種註解預設是禁用的,我們需要通過啟用配置才可以進行使用。
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true)
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
}
複製程式碼
關於相關訪問控制規則的詳細介紹和應用,我們將在以後的專題中進行逐一說明。當前只是為將來的分析打一下基礎。
三、AccessDecisionVoter元件介紹
AccessDecisionVoter
可是說是整個訪問控制、授權業務的核心。每一個AccessDecisionVoter
都需要對它所支援的訪問控制規則進行投票。投票結果只有以下三種情況:
int ACCESS_GRANTED = 1; // 贊成
int ACCESS_ABSTAIN = 0; // 棄權
int ACCESS_DENIED = -1; // 反對
複製程式碼
從AccessDecisionVoter
的介面方法簽名可以看出,其主要兩個方法分別對應的職責一個是判斷是否支援當前的訪問控制規則,另一個便是對支援的訪問規則進行投票。
在Spring Security提供的AccessDecisionVoter
實現類主要有:
- 基於Web表達是配置的
WebExpressionVoter
; - 基於角色名字首'ROLE_'對角色限制判斷的
RoleVoter
; - 根據當前Authentication授權形式判斷的
AuthenticationVoter
。 而三種Voter對應的訪問控制規則又有些略微的不同,在身份驗證模組我們瞭解到基本上每一個AuthenticationProvider
都需要定製化一種AuthenticationToken'。而在訪問控制模組中,同樣的每一個
AccessDecisionVoter也可以定製化一種
ConfigAttribute。例如,對於
WebExpressionVoter其對應的便是之前提到的
WebExpressionConfigAttribute`。
框架提供的AccessDecisionVoter一般可以滿足中小應用下的訪問控制的基本場景。如果我們當前開發的大型應用有複雜的訪問控制模型,那麼
AccessDecisionVoter
的客製化便是我們一定會面對的問題,在將來的專題裡我們會單獨針對如何客製化AccessDecisionVoter
進行說明。
四、AccessDecisionManager元件介紹
AccessDecisionManager
對於訪問控制業務的作用與AuthenticationManager
對於身份驗證的業務的作用差不多。其中一個便是對暴露了唯一的訪問控制驗證介面。而與AuthenticationManager
不同的地方是,在Spring Security中針對AuthenticationManager
只提供了一種ProviderManager
實現類,而AccessDecisionManager
缺因為有不同的表決制度分別提供了三種實現類:
AffirmativeBased
一票贊同制UnanimousBased
一票否決制ConsensusBased
少數服從多數
Spring Security在預設的配置下使用的AccessDecisionManager
是AffirmativeBased
。如果需要變更的,則可以通過配置檔案修改注入的Bean即可,比如下面的Java Config形式。
@Bean
public AccessDecisionManager accessDecisionManager() {
List<AccessDecisionVoter<? extends Object>> decisionVoters
= Arrays.asList(
new WebExpressionVoter(),
new RoleVoter(),
new AuthenticatedVoter()
);
return new UnanimousBased(decisionVoters);
}
複製程式碼
對於
AccessDecisionManager
而言,框架提供的的三種表決制度在絕大多數情況都已經足夠強大。我們對於其的瞭解便只需要集中在如何配置和管理使用的AccessDecisionVoter
便可。
結尾
訪問控制相關通常是我們使用Spring Security客製化擴充套件最頻繁的模組。所以與別的模組介紹的流程不同,本次是先將整個訪問控制模組的主要介面和元件進行基本的介紹。在後面幾期中,我們將對每個元件和其應用進行展開討論。