Spring Security(2):過濾器鏈(filter chain)的介紹


上一節中,主要講了Spring Security認證和授權的核心組件及核心方法。但是,什么時候調用這些方法呢?答案就是Filter和AOP。Spring Security在我們進行用戶認證以及授予權限的時候,通過各種各樣的攔截器來控制權限的訪問。
對於基於HttpRequest的方式對端點進行保護,我們使用一個Filter Chain來保護;對於基於方法調用進行保護,我們使用AOP來保護。本篇重點講Spring Security中過濾器鏈的種類及過濾器中如何實現的認證和授權。

 

Spring Security會默認為我們添加15個過濾器,我們可以從WebSecurity(WebSecurity是Spring Security加載的一個重要對象,將在下節具體講述)的performBuild()方法中看到過濾器鏈SecurityFilterChain的構建過程,並交由FilterChainProxy對象代理。我們從SecurityFilterChain的默認實現類DefaultSecurityFilterChain中的log看出,Spring Security由以下過濾器組成了過濾器鏈:

Creating filter chain: any request, [
  org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@7f353a0f,
  org.springframework.security.web.context.SecurityContextPersistenceFilter@4735d6e5,
  org.springframework.security.web.header.HeaderWriterFilter@314a31b0,
  org.springframework.security.web.csrf.CsrfFilter@4ef2ab73,
  org.springframework.security.web.authentication.logout.LogoutFilter@57efc6fd,
  org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@d88f893,
  org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@2cd388f5,
  org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@7ea2412c,
  org.springframework.security.web.authentication.www.BasicAuthenticationFilter@2091833,
  org.springframework.security.web.savedrequest.RequestCacheAwareFilter@4dad0eed,
  org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@16132f21,
  org.springframework.security.web.authentication.AnonymousAuthenticationFilter@1c93b51e,
  org.springframework.security.web.session.SessionManagementFilter@59edb4f5,
  org.springframework.security.web.access.ExceptionTranslationFilter@104dc1a2,
  org.springframework.security.web.access.intercept.FilterSecurityInterceptor@1de0641b
]

 

下面就是各個過濾器的功能,其中SecurityContextPersistenceFilter,UsernamePasswordAuthenticationFilter及FilterSecurityInterceptor分別對應了上節SecurityContext,AuthenticationManager,AccessDecisionManager的處理。

[WebAsyncManagerIntegrationFilter] (異步方式)提供了對securityContext和WebAsyncManager的集成。方式是通過SecurityContextCallableProcessingInterceptor的beforeConcurrentHandling(NativeWebRequest, Callable)方法來將SecurityContext設置到Callable上。其實就是把SecurityContext設置到異步線程中,使其也能獲取到用戶上下文認證信息。

 

[SecurityContextPersistenceFilter] (同步方式)在請求之前從SecurityContextRepository(默認實現是HttpSessionSecurityContextRepository)獲取信息並填充SecurityContextHolder(如果沒有,則創建一個新的ThreadLocal的SecurityContext),並在請求完成並清空SecurityContextHolder並更新SecurityContextRepository。

在Spring Security中,雖然安全上下文信息被存儲於Session中,但實際的Filter中不應直接操作Session(過濾器一般負責核心的處理流程,而具體的業務實現,通常交給其中聚合的其他實體類),而是用如HttpSessionSecurityContextRepository中loadContext(),saveContext()來存取session。

 

[HeaderWriterFilter] 用來給http響應添加一些Header,比如X-Frame-Options,X-XSS-Protection*,X-Content-Type-Options。

 

[CsrfFilter] 默認開啟,用於防止csrf攻擊的過濾器

 

[LogoutFilter] 處理注銷的過濾器

 

[UsernamePasswordAuthenticationFilter] 表單提交了username和password,被封裝成UsernamePasswordAuthenticationToken對象進行一系列的認證,便是主要通過這個過濾器完成的,即調用AuthenticationManager.authenticate()。在表單認證的方法中,這是最最關鍵的過濾器。具體過程是:

(1)調用AbstractAuthenticationProcessingFilter.doFilter()方法執行過濾器

(2)調用UsernamePasswordAuthenticationFilter.attemptAuthentication()方法

(3)調用AuthenticationManager.authenticate()方法(實際上委托給AuthenticationProvider的實現類來處理)

 

[DefaultLoginPageGeneratingFilter] & [DefaultLogoutPageGeneratingFilter] 如果沒有配置/login及login page, 系統則會自動配置這兩個Filter。


[BasicAuthenticationFilter] Processes a HTTP request's BASIC authorization headers, putting the result into the SecurityContextHolder.

 

[RequestCacheAwareFilter] 內部維護了一個RequestCache,用於緩存request請求

 

[SecurityContextHolderAwareRequestFilter] 此過濾器對ServletRequest進行了一次包裝,使得request具有更加豐富的API(populates the ServletRequest with a request wrapper which implements servlet API security methods)

 

[AnonymousAuthenticationFilter] 匿名身份過濾器,spring security為了兼容未登錄的訪問,也走了一套認證流程,只不過是一個匿名的身份。它位於身份認證過濾器(e.g. UsernamePasswordAuthenticationFilter)之后,意味着只有在上述身份過濾器執行完畢后,SecurityContext依舊沒有用戶信息,AnonymousAuthenticationFilter該過濾器才會有意義。

 

[SessionManagementFilter] 和session相關的過濾器,內部維護了一個SessionAuthenticationStrategy來執行任何與session相關的活動,比如session-fixation protection mechanisms or checking for multiple concurrent logins。

 

[ExceptionTranslationFilter] 異常轉換過濾器,這個過濾器本身不處理異常,而是將認證過程中出現的異常(AccessDeniedException and AuthenticationException)交給內部維護的一些類去處理。它
位於整個springSecurityFilterChain的后方,用來轉換整個鏈路中出現的異常,將其轉化,顧名思義,轉化以意味本身並不處理。一般其只處理兩大類異常:AccessDeniedException訪問異常和AuthenticationException認證異常。

它將Java中的異常和HTTP的響應連接在了一起,這樣在處理異常時,我們不用考慮密碼錯誤該跳到什么頁面,賬號鎖定該如何,只需要關注自己的業務邏輯,拋出相應的異常便可。如果該過濾器檢測到AuthenticationException,則將會交給內部的AuthenticationEntryPoint去處理,如果檢測到AccessDeniedException,需要先判斷當前用戶是不是匿名用戶,如果是匿名訪問,則和前面一樣運行AuthenticationEntryPoint,否則會委托給AccessDeniedHandler去處理,而AccessDeniedHandler的默認實現,是AccessDeniedHandlerImpl。

 

[FilterSecurityInterceptor] 這個過濾器決定了訪問特定路徑應該具備的權限,這些受限的資源訪需要什么權限或角色,這些判斷和處理都是由該類進行的。

(1)調用FilterSecurityInterceptor.invoke()方法執行過濾器

(2)調用AbstractSecurityInterceptor.beforeInvocation()方法

(3)調用AccessDecisionManager.decide()方法決策判斷是否有該權限

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM