Spring Security的功能能夠歸納爲兩部分,即認證和受權。html
認證就是一個用戶使用令牌(最多見的是帳號和密碼)登錄,服務器驗證這個用戶的令牌是否有效。html5
受權則是認證以後,系統根據這個用戶的信息判斷他擁有哪些權限,能訪問哪一種資源,能對資源進何種操做,並向他授予相關的權限,對沒有權限訪問的用戶進行阻止。java
這裏說的Spring Security是基於Servlet容器的。web
Spring Security的Servlet支持是基於Servlet的Filter
的。Filter能夠對請求進行處理,但Filter通常會將處理好的請求交給FilterChain
中的下一個Filter,即一個個Filter按照相應的順序組合起來造成了一個Filter鏈,從而達到對請求進行過濾/提早處理的效果。spring
當請求到達時,Servlet容器會初始化一個FilterChain
,並將請求傳遞到裏面進行處理:api
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
// do something before the rest of the application
chain.doFilter(request, response); // invoke the rest of the application
// do something after the rest of the application
}
複製代碼
通過一個個Filter處理後請求才到達Servlet處理並響應,因而可知,Filter在FilterChain
中組織的順序很是重要。安全
由於Servlet容器跟Spring的IoC容器是兩種不一樣的容器,Servlet容器沒法獲知Spring容器中各類Bean(用戶自定義Filter)的信息,也沒法直接使用這些Bean(Filter),因此須要在二者間創建橋樑,使得咱們定義的Bean(Filter)可以被Servlet容器使用。服務器
Spring提供了一種叫DelegatingFilterProxy
的Filter實現。app
它像普通的Filter同樣被插入到FilterChain
中,它的功能是將請求委託給Spring容器裏的Bean Filter來處理,從而創建起Servlet容器和Spring容器之間的橋樑。性能
例如圖中DelegatingFilterProxy
會在Spring容器中尋找Bean Filter0
,並將ServletRequest
和ServletResponse
傳遞過去:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
// Lazily get Filter that was registered as a Spring Bean
// For the example in DelegatingFilterProxy delegate is an instance of Bean Filter0
Filter delegate = getFilterBean(someBeanName);
// delegate work to the Spring Bean
delegate.doFilter(request, response);
}
複製代碼
DelegatingFilterProxy
的另外一個好處是它能夠延遲加載Bean Filter實例,由於FilterChain
會在Servlet容器啓動前初始化,這樣能夠提高Servlet容器啓動的性能。
上面提到DelegatingFilterProxy
會將請求委託給Bean Filter,而其實這裏的Bean Filter也不會直接處理請求,會將請求進一步轉發,這個Bean Filter便是FilterChainProxy
。
FilterChainProxy
是Spring Security提供的特殊Filter,它會將請求委託到另外一種FilterChain
中,即Spring的FilterChain:SecurityFilterChain
。
咱們能夠很天然地想到,SecurityFilterChain
中即是Spring的Bean Filter了,即SecurityFilter
:
這裏的SecurityFilter
就是普通的Bean,他們能夠識別本身能處理的請求並對請求處理,不然將請求傳給鏈中的下一個Filter,例如最多見的UsernamePasswordAuthenticationFilter
能夠識別處理基於表單的登錄請求。
值得注意的是,SecurityFilterChain
能夠有多條,能夠根據不一樣的請求來判斷請求應該被傳遞到哪一個SecurityFilterChain
中:
好比符合/api/**
匹配模式的URL應該被傳遞到最上面的SecurityFilterChain
中,這個請求一旦匹配到了某個上游的SecurityFilterChain
,下游的SecurityFilterChain
就不會再進行匹配。
官方文檔給出了按照Spring Security Filter排列順序的列表:
ExceptionTranslationFilter
容許將AccessDeniedException
和AuthenticationException
異常轉換爲HTTP響應,從它的名字能夠看到,它也是一個Filter,能夠被插入到SecurityFilterChain
中,這是它的工做流程:
AuthenticationException
,則會被它捕獲(見下面代碼),並調用它的startAuthentication()
方法跳轉進行認證。(圖中的SecurityContextHolder
等幾個東西屬於認證功能部分,能夠先不用管)AccessDeniedException
則對異常做出響應,通知用戶禁止訪問。從上面能夠看到,Spring Security的功能是經過Filter來實現的。每一個Filter都是一個Bean,用戶經過配置不一樣的Filter或自行實現Filter來達到保護應用/認證/受權等目的,不一樣的Filter組成了多個FilterChain,來實現不一樣的要求。