1. 程式人生 > >spring security過濾器鏈及認證流程

spring security過濾器鏈及認證流程

一、過濾器鏈

spring Security功能的實現主要是由一系列過濾器鏈相互配合完成。

下面介紹過濾器鏈中主要的幾個過濾器及其作用:

1.SecurityContextPersistenceFilter 會在請求開始時從配置好的 SecurityContextRepository 中獲取 SecurityContext,然後

把它設定給 SecurityContextHolder。在請求完成後將 SecurityContextHolder 持有的 SecurityContext 再儲存到配置好的 

SecurityContextRepository,同時清除 securityContextHolder 所持有的 SecurityContext;

2.UsernamePasswordAuthenticationFilter 用於處理來自表單提交的認證。該表單必須提供對應的使用者名稱和密碼,其內部還有

登入成功或失敗後進行處理的 AuthenticationSuccessHandlerAuthenticationFailureHandler,這些都可以根據需求做相

關改變;

3.FilterSecurityInterceptor 是用於保護Http 資源的,它需要一個AccessDecisionManager和一個AuthenticationManager

引用。它會從 SecurityContextHolder 獲取 Authentication,然後通過 SecurityMetadataSource 可以得知當前請求是否在請

求受保護的資源。對於請求那些受保護的資源,如果Authentication.isAuthenticated()返回false或者FilterSecurityInterceptor

的alwaysReauthenticate 屬性為 true,那麼將會使用其引用的 AuthenticationManager 再認證一次,認證之後再使用認證後

的 Authentication 替換 SecurityContextHolder 中擁有的那個。然後就是利用 AccessDecisionManager 進行許可權的檢查;

4.ExceptionTranslationFilter 能夠捕獲來自 FilterChain 所有的異常,並進行處理。

但是它只會處理兩類異常:AuthenticationException 和 AccessDeniedException,其它的異常它會繼續丟擲。

--- 如果捕獲到的是 AuthenticationException,那麼將會使用其對應的 AuthenticationEntryPoint 的commence()處理。在處

理之前,ExceptionTranslationFilter先使用 RequestCache 將當前的HttpServerletRequest的資訊儲存起來,以至於使用者成功

登入後可以跳轉到之前的介面;

--- 如果捕獲到的是 AccessDeniedException,那麼將視當前訪問的使用者是否已經登入認證做不同的處理,如果未登入,則會使

用關聯的 AuthenticationEntryPoint 的 commence()方法進行處理,否則將使用關聯的 AccessDeniedHandler 的handle()方

法進行處理。

說明:

1、AuthenticationEntryPoint 是在使用者沒有登入時用於引導使用者進行登入認證的;

2、AccessDeniedHandler 用於在使用者已經登入了,但是訪問其自身沒有許可權的資源時做出對應的處理 [預設實現類:

 AccessDeniedHandlerImpl];

 3、RequestCache [預設實現類:HttpSessionRequestCache]會將 HttpServletRequest 相關資訊封裝為一個 

  SavedRequest 並儲存到 HttpSession中;

二、認證流程

認證流程分為登入流程和登出流程,下面將一一敘述。

注意:這裡的登入方式為"帳號+密碼";箭頭代表整個流程執行方向)

1)登入流程

---> SecurityContextPersistenceFilter(作用在第一節已經介紹)

---> UsernamePasswordAuthenticationFilter 

(先獲取使用者名稱和密碼,並將其封裝成UsernamePasswordToken,然後呼叫AuthenticationManager進行驗證) 

---> AuthenticationManager 

(根據token型別選擇合適的AuthenticationProvider來處理認證請求)  [預設實現類:ProviderManager]

AuthenticationManager是一個用來處理請求的介面,它自己不直接處理認證請求,而是委託給其所配置的Authentication

Provider列表,然後會依次使用每一個 AuthenticationProvider 進行認證,如果有一個AuthenticationProvider 認證後的結果

不為 null,則表示該AuthenticationProvider已經認證成功,之後的AuthenticationProvider 將不再繼續認證。然後直接以該 

AuthenticationProvider 的認證結果作為 ProviderManager 的認證結果。如果所有的 AuthenticationProvider 的認證結果都

為null,則表示認證失敗,將丟擲一個 ProviderNotFoundException。

---> AuthenticationProvider 

(請求認證處理) [預設實現類:DaoAuthencationProvider]

DaoAuthenticationProvider認證過程:

DaoAuthenticationProvider先呼叫UserDetailsService 的loadUserByUsername()方法獲取UserDetails,獲取後再與

UsernamePasswordAuthenticationFilter獲取的username和password進行比較;如果認證通過後會將該 UserDetails 賦給認

證通過的 Authentication的principal,然後再把該 Authentication 存入到 SecurityContext 中。預設情況下,在認證成功後

ProviderManager也將清除返回的Authentication中的憑證資訊。

注意在這裡面根據需要增加[自定義關鍵類(UserDetailService):實現UserDetailService介面並複寫loadUserByUsername()]

問:為什麼AuthenticationManager不直接認證請求?

答:因為token有多種型別。比如最簡單的UsernamePasswordAuthenticationToken,還有spring social的token;

---> Authentication物件

Spring Security使用一個Authentication 物件來描述當前使用者的相關資訊。SecurityContextHolder中持有的是當前使用者的 

SecurityContext,而 SecurityContext 持有的是代表當前使用者相關資訊的 Authentication 的引用。這個 Authentication 物件

不需要我們自己去建立,在與系統互動的過程中,Spring Security會自動為我們建立相應的Authentication物件,然後賦值給當

前的SecurityContext。

2)登出流程

1、使HttpSession失效;

2、清除所有已經配置的remember-me認證;

3、清除SecurityContextHolder中的user資訊,並設定Authentication中的Authenticated屬性為false;

4、跳轉到指定url;