Spring Security(二) -- Spring Security的Filter
作者: 屈定
博客: http://mrdear.cn/
上一篇學習了Spring Security是如何攔截請求,並把請求轉向到Filter鏈的,該篇就主要學習下這些Filter鏈的節點的作用.
下面是之前配置的內容,本文也是對這些內容 的執行分析.
<security:http > <security:intercept-url pattern="/**" access="hasRole(ROLE_USER)"/> <security:form-login/> <security:http-basic/> <security:logout/></security:http> <security:authentication-manager> <security:authentication-provider> <security:user-service> <security:user name="user" password="123456" authorities="ROLE_USER"/> <security:user name="admin" password="123456" authorities="ROLE_USER, ROLE_ADMIN"/> </security:user-service> </security:authentication-provider> </security:authentication-manager>
1.Filter鏈的由來
由上文可知每一個security:http標籤實際上對應的是一個SecurityFilterChain的類,也就是一條Filter鏈,可以通過其http屬性指明其作用的URL,否則作用域全部的URL,如下配置,該security:http會產生一個對/login下的所有請求Filter鏈.
<security:http pattern="/login/**"> ****** </security:http>
打個斷點可以很清楚的看到該Filter鏈
2.SecurityContextPersistenceFilter
該類在所有的Filter之前,是從SecurityContextRepository中取出用戶認證信息,默認實現類為HttpSessionSecurityContextRepository,其會從Session中取出已認證用戶的信息,提高效率,避免每一次請求都要查詢用戶認證信息.
取出之後會放入SecurityContextHolder中,以便其他filter使用,SecurityContextHolder使用ThreadLocal存儲用戶認證信息,保證了線程之間的信息隔離,最後再finally中清除該信息.
可以配置http的security-context-repository-ref屬性來自己控制獲取到已認證用戶信息的方式,比如使用redis存儲session等,當不適用session的話最好配置為NullSecurityContextRepository,避免佔用伺服器內存.
3.WebAsyncManagerIntegrationFilter
提供了對securityContext和WebAsyncManager的集成,其會把SecurityContext設置到非同步線程中,使其也能獲取到用戶上下文認證信息.
4.HeaderWriterFilter
其會往該請求的Header中添加相應的信息,在http標籤內部使用security:headers來控制.
5.CsrfFilter
Csrf,跨站請求偽造,了解不是很深,只知道B網站使用A網站的可信Cookie發起請求,從而完成認證,偽造出正當請求.
驗證方式是通過客戶端傳來的token與服務端存儲的token進行對比,來判斷是否為偽造請求,有興趣的可以查看源代碼研究下.
6.LogoutFilter
匹配URL,默認為/logout,匹配成功後則用戶退出,清除認證信息.如果有自己的退出邏輯,那麼這個過濾器可以disable
7.UsernamePasswordAuthenticationFilter
登錄認證過濾器,默認是對/login的POST請求進行認證,首先該方法會先調用attemptAuthentication嘗試認證獲取一個Authentication的認證對象,然後通過sessionStrategy.onAuthentication執行持久化,也就是保存認證信息,轉向下一個Filter,最後調用successfulAuthentication執行認證後事件.
attemptAuthentication
該方法是認證的主要方法,認證是委託配置的authentication-manager->authentication-provider進行.
比如對於該Demo配置的為如下,則默認使用的manager為ProviderManager,使用的provider為DaoAuthenticationProvider,userDetailService為InMemoryUserDetailsManager也就是從內存中獲取用戶認證信息,也就是下面xml配置的user與admin信息.
<security:authentication-manager> <security:authentication-provider> <security:user-service> <security:user name="user" password="123456" authorities="ROLE_USER"/> <security:user name="admin" password="123456" authorities="ROLE_USER, ROLE_ADMIN"/> </security:user-service> </security:authentication-provider> </security:authentication-manager>
認證基本流程為UserDeatilService根據用戶名獲取到認證用戶的信息,然後通過UserDetailsChecker.check對用戶進行狀態校驗,最後通過additionalAuthenticationChecks方法對用戶進行密碼校驗成功後完成認證.返回一個認證對象.
都是面向介面編程,所以用戶可以很輕鬆的擴展自己的驗證方式.
8.DefaultLoginPageGeneratingFilter
當請求為登錄請求時,生成簡單的登錄頁面返回,有自己的登錄邏輯的話同樣可以disable
9.BasicAuthenticationFilter
Http Basci認證的支持,該認證會把用戶名密碼使用base64編碼後放入header中傳輸,如下所示,認證成功後會把用戶信息放入SecurityContextHolder中.
* Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
10.RequestCacheAwareFilter
恢復被打斷的請求,具體未研究
11.SecurityContextHolderAwareRequestFilter
針對Servlet api不同版本做的一些包裝
12.AnonymousAuthenticationFilter
當SecurityContextHolder中認證信息為空,則會創建一個匿名用戶存入到SecurityContextHolder中
13.SessionManagementFilter
與登錄認證攔截時作用一樣,持久化用戶登錄信息,可以保存到session中,也可以保存到cookie或者redis中.
14.ExceptionTranslationFilter
異常攔截,其處在Filter鏈後部分,只能攔截其後面的節點並且著重處理AuthenticationException與AccessDeniedException兩個異常.可以在此處定義一個entryPoint,對錯誤請求返回403.
15.FilterSecurityInterceptor
主要是授權驗證,方法為beforeInvocation,在其中調用
Collection<ConfigAttribute> attributes = this.obtainSecurityMetadataSource() .getAttributes(object);
獲取到所配置資源訪問的授權信息,對於上述配置,獲取到的則為hasRole(ROLE_USER),然後根據SecurityContextHolder中存儲的用戶信息來決定其是否有許可權,沒許可權則返回403,具體想了解可以關注HttpConfigurationBuilder.createFilterSecurityInterceptor()方法,分析其創建流程載入了哪些數據,或者分析SecurityExpressionOperations的子類,其是許可權鑒定的實現方法.
總結
整個認證授權流程如下圖所示,圖是網上盜的
因為是學習方面,使用的不是很多,如有錯誤請指出,以防誤人子弟.
簡單來說,作為用戶需要關心的地方是
- 登錄驗證UsernamePasswordAuthenticationFilter
- 訪問驗證BasicAuthenticationFilter
- 許可權驗證FilterSecurityInterceptor
下一篇則講述利用這三個驗證實現JWT驗證.
關於這些過濾器更詳細的內容可參考博客:博客專欄 - Spring Security簡介
推薦閱讀:
※Spring Security(一) -- 初識Spring Security
※史上最簡單的SpringCloud教程 | 第八篇: 消息匯流排(Spring Cloud Bus)
※Spring Boot中使用Flyway來管理資料庫版本
※Spring Security源碼分析五:Spring Security實現簡訊登錄
※用小說的形式講解Spring(1) —— 為什麼需要依賴注入
TAG:Spring |