Spring Security 實戰乾貨:圖解Spring Security中的Servlet過濾器體系
阿新 • • 發佈:2020-07-06
## 1. 前言
我在[Spring Security 實戰乾貨:內建 Filter 全解析](https://www.felord.cn/spring-security-filters.html)對**Spring Security**的內建過濾器進行了羅列,但是**Spring Security**真正的過濾器體系才是我們瞭解它是如何進行"認證"、“授權”、“防止利用漏洞”的關鍵。
## 2. Servlet Filter體系
這裡我們以**Servlet Web**為討論目標,**Reactive Web**暫不討論。我們先來看下最基礎的**Servlet**體系,在**Servlet**體系中客戶端發起一個請求過程是經過0到N個`Filter`然後交給`Servlet`處理。
![servlet過濾器鏈](https://img2020.cnblogs.com/other/1739473/202007/1739473-20200706111603231-1307976421.png)
`Filter`不但可以修改`HttpServletRequest`和`HttpServletResponse`,可以讓我們在請求響應的前後做一些事情,甚至可以終止過濾器鏈`FilterChain`的傳遞。
```java
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
// 請求被servlet 處理前
if(condition){
// 根據條件來進入下一個過濾器
chain.doFilter(request, response);
}
// 請求被執行完畢後處理一些事情
}
```
由於`Filter`僅影響下游**Filters**和**Servlet**,因此每個`Filter`呼叫的順序非常重要。**Spring Security**正是根據這個個特性來實現一系列的安全功能。接下來我們來看看它們是如何結合的。
## 3. GenericFilterBean
在該系列的文章開篇我對[Spring Security和Shiro進行了簡單的對比](https://www.felord.cn/pre-learn-spring-security-shiro.html)。**Spring Security**利用了**Spring IOC**和**AOP**的特性而無法脫離**Spring**獨立存在,而**Apache Shiro**可以獨立存在。所以今天我們要一探究竟,看看他們是如何結合的。
**Spring**結合**Servlet Filter**自然是要為**Servlet Filter**注入**Spring Bean**的特性,所以就搞出了一個抽象**Filter Bean**,這個抽象過濾器`GenericFilterBean`並不是在**Spring Security**下,而是**Spring Web**體系中,類圖如下:
![image-20200701162747774](https://img2020.cnblogs.com/other/1739473/202007/1739473-20200706111603427-514643250.png)
從類圖上看`Filter`介面已經被注入了多個**Spring Bean**的特性,納入了**Spring Bean**生命週期,使得**Spring IoC**容器能夠充分的管理`Filter`。
## 4. DelegatingFilterProxy
我們希望**Servlet**能夠按照它自己的標準來註冊到過濾器鏈中工作,但是同時也希望它能夠被**Spring IoC**管理,所以Spring提供了一個`GenericFilterBean`的實現`DelegatingFilterProxy`。我們可以將原生的**Servlet Filter**或者**Spring Bean Filter**委託給`DelegatingFilterProxy`,然後在結合到**Servlet FilterChain**中。
![DelegatingFilterProxy](https://img2020.cnblogs.com/other/1739473/202007/1739473-20200706111603688-1405642231.png)
## 5. SecurityFilterChain
針對不同符合[Ant Pattern](https://felord.cn/spring-security-ant-url.html)的請求可能會走不同的過濾器鏈,比如登入會去驗證,然後返回登入結果;管理後臺的介面走後臺的安全邏輯,應用客戶端的介面走客戶端的安全邏輯。**Spring Security**提供了一個`SecurityFilterChain`介面來滿足被匹配`HttpServletRequest`走特定的過濾器鏈的需求。
```java
public interface SecurityFilterChain {
// 判斷請求 是否符合該過濾器鏈的要求
boolean matches(HttpServletRequest request);
// 對應的過濾器鏈