Spring Security 安全過濾器
1. 前言
上一節(jié)中我們了解到了 Spring Security 安全框架是由一系列有序的安全過濾器組成的,本節(jié)將重點(diǎn)討論 Spring Security 內(nèi)置安全過濾器的順序及含義。
Spring 將自己體系內(nèi)的過濾器交由「過濾器代理 FilterChainProxy」管理,Spring Security 在「過濾器代理 FilterChainProxy」中加入了「安全過濾器鏈 SecurityFilterChain」實(shí)現(xiàn)安全保護(hù)功能。
在 Spring Security 各個(gè)模塊中,內(nèi)置已實(shí)現(xiàn)了一系列的「安全過濾器」,可以滿足常見的認(rèn)證、鑒權(quán)等功能需求。
在 Spring Security 5.3.2 中,共內(nèi)置了 33 個(gè)安全過濾器。
本節(jié)主要討論 Spring Security 內(nèi)置的安全過濾器。
2. 內(nèi)置安全過濾器
2.1 內(nèi)置安全過濾器的聲明
Spring Security 中的 SecurityFilterChain 對(duì)象,是通過 HttpSecurity 類來使用,它還提供了安全過濾器增、減的調(diào)用接口。
如前文所述,安全過濾器的執(zhí)行順序是至關(guān)重要的,而順序的確定是由 FilterComparator 對(duì)象實(shí)現(xiàn)的。
FilterComparator 類的全路徑為 org.springframework.security.config.annotation.web.builders.FilterComparator。
在其構(gòu)造的時(shí)候配置了過濾器的基本順序,代碼如下:
FilterComparator() {
FilterComparator.Step order = new FilterComparator.Step(100, 100);
this.put(ChannelProcessingFilter.class, order.next());
this.put(ConcurrentSessionFilter.class, order.next());
this.put(WebAsyncManagerIntegrationFilter.class, order.next());
this.put(SecurityContextPersistenceFilter.class, order.next());
this.put(HeaderWriterFilter.class, order.next());
...
this.put(SessionManagementFilter.class, order.next());
this.put(ExceptionTranslationFilter.class, order.next());
this.put(FilterSecurityInterceptor.class, order.next());
this.put(SwitchUserFilter.class, order.next());
}
注意,以上
FilterComparator中的定義僅作為內(nèi)置過濾器排序的依據(jù),并不等于過濾器的真正注入。
除了內(nèi)置的過濾器外,當(dāng)我們需要添加自定義過濾器的時(shí)候,也需要依賴 FilterComparator 對(duì)象完成順序的配置。實(shí)際開發(fā)時(shí)可用以下方法完成向指定順位插入過濾器的功能:http.addFilterAfter、http.addFilterBefore、http.addFilter、http.addFilterAt(http 為 HttpSecurity 實(shí)例)。
另一方面,HttpSecurity 還為各個(gè)內(nèi)置過濾器提供了配置接口。例如:針對(duì) HeaderWriterFilter 提供了 headers() 方法,用于獲取或?yàn)?HeaderWriterFilter 配置參數(shù),例如設(shè)置響應(yīng)緩存時(shí)效 Expires 等 。HttpSecurity 在構(gòu)建時(shí),會(huì)根據(jù)已有的配置信息逐一對(duì) Filter 進(jìn)行實(shí)例化。HttpSecurity 還完成了對(duì)請(qǐng)求地址的配置,通過 RequestMatcherConfigurer 對(duì)象使請(qǐng)求地址與 Filter 匹配。
2.2 內(nèi)置過濾器總覽

| 順序號(hào) | 過濾器名稱 | 簡(jiǎn)述 |
|---|---|---|
| 1 | ChannelProcessingFilter | 檢查 web 請(qǐng)求通道,如:http、https |
| 2 | ConcurrentSessionFilter | 檢查 Session 狀態(tài),更新 Session 最后訪問時(shí)間 |
| 3 | WebAsyncManagerIntegrationFilter | 關(guān)聯(lián) Spring Web 上下文和 Spring Security 上下文 |
| 4 | SecurityContextPersistenceFilter | 從 Session 構(gòu)建 SecurityContext |
| 5 | HeaderWriterFilter | 往請(qǐng)求頭或響應(yīng)頭里寫入信息 |
| 6 | CorsFilter | 跨域請(qǐng)求頭 |
| 7 | CsrfFilter | 跨站請(qǐng)求偽造 |
| 8 | LogoutFilter | 注銷過濾器 |
| 9 | OAuth2AuthorizationRequestRedirectFilter | OAuth2 請(qǐng)求重定向 |
| 10 | Saml2WebSsoAuthenticationRequestFilter | SAML2 單點(diǎn)登錄認(rèn)證請(qǐng)求過濾器 |
| 11 | X509AuthenticationFilter | X509 認(rèn)證過濾器 |
| 12 | AbstractPreAuthenticatedProcessingFilter | 預(yù)認(rèn)證處理 |
| 13 | CasAuthenticationFilter | 單點(diǎn)認(rèn)證過濾器 |
| 14 | OAuth2LoginAuthenticationFilter | OAuth2 認(rèn)證過濾器 |
| 15 | Saml2WebSsoAuthenticationFilter | SAML2 單點(diǎn)登錄認(rèn)證過濾器 |
| 16 | UsernamePasswordAuthenticationFilter | 用戶名密碼認(rèn)證過濾器 |
| 17 | ConcurrentSessionFilter | 檢查 Session 狀態(tài),更新 Session 最后訪問時(shí)間。第二次出現(xiàn)。 |
| 18 | OpenIDAuthenticationFilter | Open ID 認(rèn)證過濾器 |
| 19 | DefaultLoginPageGeneratingFilter | 生成 /login 頁面 |
| 20 | DefaultLogoutPageGeneratingFilter | 生成 /logout 頁面 |
| 21 | DigestAuthenticationFilter | 數(shù)字簽名認(rèn)證過濾器 |
| 22 | BearerTokenAuthenticationFilter | Bearer Token 認(rèn)證過濾器 |
| 23 | BasicAuthenticationFilter | 基本身份認(rèn)證過濾器 |
| 24 | RequestCacheAwareFilter | 緩存請(qǐng)求狀態(tài)過濾器 |
| 25 | SecurityContextHolderAwareRequestFilter | 安全上下文請(qǐng)求輔助過濾器 |
| 26 | JaasApiIntegrationFilter | JAAS 認(rèn)證授權(quán)過濾器 |
| 27 | RememberMeAuthenticationFilter | 實(shí)現(xiàn)記住我功能 |
| 28 | AnonymousAuthenticationFilter | 匿名認(rèn)證過濾器 |
| 29 | OAuth2AuthorizationCodeGrantFilter | OAuth2 認(rèn)證授權(quán)碼 |
| 30 | SessionManagementFilter | 管理 Session |
| 31 | ExceptionTranslationFilter | 異常事件處理過濾器 |
| 32 | FilterSecurityInterceptor | 動(dòng)態(tài)權(quán)限配置 |
| 33 | SwitchUserFilter | 切換賬戶 |
2.3 常用內(nèi)置過濾器的具體說明
內(nèi)置過濾器的參數(shù)設(shè)置通過 HttpSecurity 相應(yīng)的配置方法完成。
2.3.1 ChannelProcessingFilter
ChannelProcessingFilter 的用于檢測(cè)請(qǐng)求的通道,例如 Http 或 Https 等,可以實(shí)現(xiàn)訪問請(qǐng)求在不同通道間的跳轉(zhuǎn)。
ChannelProcessingFilter 的配置通過 HttpSecurity.requiresChannel() 方法獲取。
例如:強(qiáng)制使用 Https 通道訪問。
http.requiresChannel().antMatchers("/users").requiresSecure();
2.3.2 ConcurrentSessionFilter
此過濾器在默認(rèn)情況下出現(xiàn)兩次,其工作內(nèi)容大致分兩步:
- 判斷 Session 是否存在,如果存在則獲取,否則結(jié)束;
- 判斷 Session 是否過期,如果過期則執(zhí)行退出操作,否則更新 Session 時(shí)間。
ConcurrentSessionFilter 的配置通過 HttpSecurity.sessionManagement() 方法獲取。
例如:設(shè)置 Session 無效時(shí)的跳轉(zhuǎn) URL。
http.sessionManagement().invalidSessionUrl("/login");
2.3.3 WebAsyncManagerIntegrationFilter
WebAsyncManagerIntegrationFilter 用于關(guān)聯(lián) SecurityContext 上下文。
此過濾器無配置公布的方法。
2.3.4 SecurityContextPersistenceFilter
SecurityContextPersistenceFilter 用于從 Session 構(gòu)建 SecurityContext。具體分為兩步:
- 請(qǐng)求開始時(shí),將 SecurityContextRepository 中的 SecurityContext 對(duì)象存入 SecurityContextHolder;
- 請(qǐng)求完成時(shí),清理 SecurityContextHolder 中的 SecurityContext 對(duì)象,并產(chǎn)生新的 SecurityContext 對(duì)象放入到 SecurityContextRepository 中,以保證并發(fā)環(huán)境下的數(shù)據(jù)一致性。
SecurityContextPersistenceFilter 的配置通過 HttpSecurity.securityContext() 方法獲取。
2.3.5 HeaderWriterFilter
HeaderWriterFilter 用于往請(qǐng)求頭或響應(yīng)頭里寫入信息。
HeaderWriterFilter 的配置通過 HttpSecurity.headers() 方法獲取。默認(rèn)支持的 Header 包括:
Header [name: X-Content-Type-Options, values: [nosniff]]
Header [name: X-XSS-Protection, values: [1; mode=block]]
Header [name: Cache-Control, values: [no-cache, no-store, max-age=0, must-revalidate]]
Header [name: Pragma, values: [no-cache]]
Header [name: Expires, values: [0]]
2.3.6 CorsFilter
CorsFilter 用于配置跨域請(qǐng)求策略。當(dāng)一個(gè)請(qǐng)求中,來源與目標(biāo)的協(xié)議、主機(jī)名、端口三者任一不同,即為跨域,在實(shí)際開發(fā)中如果遇到類似 header is present on the requested resource. 的錯(cuò)誤時(shí),往往是因?yàn)榭缬蚺渲貌徽_導(dǎo)致。
CorsFilter 的配置通過 HttpSecurity.cors() 方法獲取。例如,禁用跨域驗(yàn)證:
http.cors().disable();
2.3.7 CsrfFilter
CsrfFilter 用于驗(yàn)證消息來源,防范跨站請(qǐng)求偽造,此項(xiàng)功能需要前端的配合。
CsrfFilter 的配置通過 HttpSecurity.csrf() 方法獲取。例如,禁用 Csrf:
http.csrf().disable();
2.3.8 LogoutFilter
LogoutFilter 用于注銷登錄狀態(tài)。
LogoutFilter 的配置通過 HttpSecurity.logout() 方法獲取。例如,設(shè)置退出后的跳轉(zhuǎn)頁面。
http.logout().logoutSuccessUrl("/login");
2.3.9 UsernamePasswordAuthenticationFilter
UsernamePasswordAuthenticationFilter 用于處理用戶名、密碼認(rèn)證。
UsernamePasswordAuthenticationFilter 的配置通過 HttpSecurity.formLogin() 方法獲取。例如,設(shè)置用戶名參數(shù)為「mobile」:
http.formLogin().usernameParameter("mobile")
UsernamePasswordAuthenticationFilter Spring Security 認(rèn)證中較為常用的過濾器,我們會(huì)在后續(xù)章節(jié)重點(diǎn)展開。
2.3.10 ExceptionTranslationFilter
ExceptionTranslationFilter 用于異常事件處理。異常事件有前述過濾器拋出,異常共分為 2 類,一類是認(rèn)證異常,另一類是權(quán)限異常。
ExceptionTranslationFilter 的配置通過 HttpSecurity.exceptionHandling() 方法獲取。
ExceptionTranslationFilter 同樣較為常用,將在后續(xù)章節(jié)中重點(diǎn)展開。
3 增加自定義的 Filter
在 HttpSecurity 對(duì)象中增加自定義 Filter 可用于實(shí)現(xiàn)認(rèn)證方式的擴(kuò)展等場(chǎng)景,擴(kuò)展 Filter 有兩步很重要,第一是實(shí)現(xiàn) javax.servlet.Filter 接口;第二是指定新過濾器的位置。
例如,擴(kuò)展自定義接口 SimpleFilter。
- 自定義接口類
public class SimpleFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("In SimpleFilter");
}
}
- 加入到指定位置,比如加在
UsernamePasswordAuthenticationFilter之前
http.addFilterBefore(new SimpleFilter(), UsernamePasswordAuthenticationFilter.class);
4. 小結(jié)
本節(jié)我們介紹了 Spring Security 過濾器的作用及其順序,主要的知識(shí)點(diǎn)有:
- Spring Security 通過擴(kuò)展 Spring 過濾器實(shí)現(xiàn)安全相關(guān)業(yè)務(wù)邏輯;
- Spring Security 目前原生實(shí)現(xiàn)了 33 個(gè)過濾器,每個(gè)過濾器有固定的順序及應(yīng)用場(chǎng)景;
- Spring Security 可以的插入自定義的過濾器,并且指定過濾器的位置。
Spring Security 過濾器幾乎是所有安全功能的核心,在后續(xù)章節(jié)中還會(huì)圍繞過濾器展開討論。下節(jié)我們將介紹 Spring Security 的異常回收機(jī)制。
童雷 ·
2025 imooc.com All Rights Reserved |