上一文咱們使用 Spring Security 實現了各類登陸聚合的場面。其中咱們是經過在 UsernamePasswordAuthenticationFilter
以前一個自定義的過濾器實現的。我怎麼知道自定義過濾器要加在 UsernamePasswordAuthenticationFilter
以前。我在這個系列開篇說了 Spring Security 權限控制的一個核心關鍵就是 過濾器鏈 ,這些過濾器以下圖進行過濾傳遞,甚至比這個更復雜!這只是一個最小單元。html
Spring Security 內置了一些過濾器,他們各有各的本事。若是你掌握了這些過濾器,不少實際開發中的需求和問題都很容易解決。今天咱們來見識一下這些內置的過濾器。java
在 Spring Security 初始化核心過濾器時 HttpSecurity
會經過將 Spring Security 內置的一些過濾器以 FilterComparator
提供的規則進行比較按照比較結果進行排序註冊。web
FilterComparator
維護了一個順序的註冊表 filterToOrder
。spring
FilterComparator() { Step order = new Step(INITIAL_ORDER, ORDER_STEP); put(ChannelProcessingFilter.class, order.next()); put(ConcurrentSessionFilter.class, order.next()); put(WebAsyncManagerIntegrationFilter.class, order.next()); put(SecurityContextPersistenceFilter.class, order.next()); put(HeaderWriterFilter.class, order.next()); put(CorsFilter.class, order.next()); put(CsrfFilter.class, order.next()); put(LogoutFilter.class, order.next()); filterToOrder.put( "org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter", order.next()); filterToOrder.put( "org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationRequestFilter", order.next()); put(X509AuthenticationFilter.class, order.next()); put(AbstractPreAuthenticatedProcessingFilter.class, order.next()); filterToOrder.put("org.springframework.security.cas.web.CasAuthenticationFilter", order.next()); filterToOrder.put( "org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter", order.next()); filterToOrder.put( "org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationFilter", order.next()); put(UsernamePasswordAuthenticationFilter.class, order.next()); put(ConcurrentSessionFilter.class, order.next()); filterToOrder.put( "org.springframework.security.openid.OpenIDAuthenticationFilter", order.next()); put(DefaultLoginPageGeneratingFilter.class, order.next()); put(DefaultLogoutPageGeneratingFilter.class, order.next()); put(ConcurrentSessionFilter.class, order.next()); put(DigestAuthenticationFilter.class, order.next()); filterToOrder.put( "org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter", order.next()); put(BasicAuthenticationFilter.class, order.next()); put(RequestCacheAwareFilter.class, order.next()); put(SecurityContextHolderAwareRequestFilter.class, order.next()); put(JaasApiIntegrationFilter.class, order.next()); put(RememberMeAuthenticationFilter.class, order.next()); put(AnonymousAuthenticationFilter.class, order.next()); filterToOrder.put( "org.springframework.security.oauth2.client.web.OAuth2AuthorizationCodeGrantFilter", order.next()); put(SessionManagementFilter.class, order.next()); put(ExceptionTranslationFilter.class, order.next()); put(FilterSecurityInterceptor.class, order.next()); put(SwitchUserFilter.class, order.next()); }
這些就是全部內置的過濾器。 他們是經過下面的方法獲取本身的序號:json
private Integer getOrder(Class<?> clazz) { while (clazz != null) { Integer result = filterToOrder.get(clazz.getName()); if (result != null) { return result; } clazz = clazz.getSuperclass(); } return null; }
經過過濾器的類全限定名從註冊表 filterToOrder
中獲取本身的序號,若是沒有直接獲取到序號經過遞歸獲取父類在註冊表中的序號做爲本身的序號,序號越小優先級越高。上面的過濾器並不是所有會被初始化。有的須要額外引入一些功能包,有的看 HttpSecurity
的配置狀況。 在上一篇文章中。咱們禁用了 CSRF
功能,就意味着 CsrfFilter
不會被註冊。segmentfault
接下來咱們就對這些內置過濾器進行一個系統的認識。咱們將按照默認順序進行講解。後端
ChannelProcessingFilter
一般是用來過濾哪些請求必須用 https
協議, 哪些請求必須用 http
協議, 哪些請求隨便用哪一個協議都行。它主要有兩個屬性:跨域
ChannelDecisionManager
用來判斷請求是否符合既定的協議規則。它維護了一個 ChannelProcessor
列表 這些ChannelProcessor
是具體用來執行 ANY_CHANNEL
策略 (任何通道均可以), REQUIRES_SECURE_CHANNEL
策略 (只能經過https
通道), REQUIRES_INSECURE_CHANNEL
策略 (只能經過 http
通道)。FilterInvocationSecurityMetadataSource
用來存儲 url 與 對應的ANY_CHANNEL
、REQUIRES_SECURE_CHANNEL
、REQUIRES_INSECURE_CHANNEL
的映射關係。ChannelProcessingFilter
經過 HttpScurity#requiresChannel()
等相關方法引入其配置對象 ChannelSecurityConfigurer
來進行配置。緩存
ConcurrentSessionFilter
主要用來判斷session
是否過時以及更新最新的訪問時間。其流程爲:安全
session
檢測,若是不存在直接放行去執行下一個過濾器。存在則進行下一步。sessionid
從SessionRegistry
中獲取SessionInformation
,從SessionInformation
中獲取session
是否過時;沒有過時則更新SessionInformation
中的訪問日期;doLogout()
方法,這個方法會將session
無效,並將 SecurityContext
中的Authentication
中的權限置空,同時在SecurityContenxtHoloder
中清除SecurityContext
而後查看是否有跳轉的 expiredUrl
,若是有就跳轉,沒有就輸出提示信息。ConcurrentSessionFilter
經過SessionManagementConfigurer
來進行配置。
WebAsyncManagerIntegrationFilter
用於集成SecurityContext到Spring異步執行機制中的WebAsyncManager。用來處理異步請求的安全上下文。具體邏輯爲:
WebAsyncManager
,若是還沒有綁定,先作綁定。asyncManager
中獲取 key
爲 CALLABLE_INTERCEPTOR_KEY
的安全上下文多線程處理器 SecurityContextCallableProcessingInterceptor
, 若是獲取到的爲 null
,SecurityContextCallableProcessingInterceptor
並綁定 CALLABLE_INTERCEPTOR_KEY
註冊到 asyncManager
中。這裏簡單說一下 SecurityContextCallableProcessingInterceptor
。它實現了接口 CallableProcessingInterceptor
,
當它被應用於一次異步執行時,beforeConcurrentHandling()
方法會在調用者線程執行,該方法會相應地從當前線程獲取SecurityContext
,而後被調用者線程中執行邏輯時,會使用這個 SecurityContext
,從而實現安全上下文從調用者線程到被調用者線程的傳輸。
WebAsyncManagerIntegrationFilter
經過 WebSecurityConfigurerAdapter#getHttp()
方法添加到 HttpSecurity
中成爲 DefaultSecurityFilterChain
的一個鏈節。
SecurityContextPersistenceFilter
主要控制 SecurityContext
的在一次請求中的生命週期 。 請求來臨時,建立SecurityContext
安全上下文信息,請求結束時清空 SecurityContextHolder
。
SecurityContextPersistenceFilter
經過 HttpScurity#securityContext()
及相關方法引入其配置對象 SecurityContextConfigurer
來進行配置。
HeaderWriterFilter
用來給 http
響應添加一些 Header
,好比 X-Frame-Options
, X-XSS-Protection
,X-Content-Type-Options
。
你能夠經過 HttpScurity#headers()
來定製請求Header
。
跨域相關的過濾器。這是Spring MVC Java
配置和XML
命名空間 CORS
配置的替代方法, 僅對依賴於spring-web
的應用程序有用(不適用於spring-webmvc
)或 要求在javax.servlet.Filter
級別進行CORS檢查的安全約束連接。這個是目前官方的一些解讀,可是我仍是不太清楚實際機制。
你能夠經過 HttpSecurity#cors()
來定製。
CsrfFilter
用於防止csrf
攻擊,先後端使用json交互須要注意的一個問題。
你能夠經過 HttpSecurity.csrf()
來開啓或者關閉它。在你使用 jwt
等 token
技術時,是不須要這個的。
LogoutFilter
很明顯這是處理註銷的過濾器。
你能夠經過 HttpSecurity.logout()
來定製註銷邏輯,很是有用。
和上面的有所不一樣,這個須要依賴 spring-scurity-oauth2
相關的模塊。該過濾器是處理 OAuth2
請求首選重定向相關邏輯的。之後會我會帶大家認識它,請多多關注公衆號:Felordcn
。
這個須要用到 Spring Security SAML
模塊,這是一個基於 SMAL
的 SSO
單點登陸請求認證過濾器。
SAML
即安全斷言標記語言,英文全稱是 Security Assertion Markup Language
。它是一個基於 XML
的標準,用於在不一樣的安全域(security domain
)之間交換認證和受權數據。在 SAML
標準定義了身份提供者 (identity provider
) 和服務提供者 (service provider
),這二者構成了前面所說的不一樣的安全域。 SAML
是 OASIS
組織安全服務技術委員會(Security Services Technical Committee) 的產品。
SAML
(Security Assertion Markup Language)是一個 XML
框架,也就是一組協議,能夠用來傳輸安全聲明。好比,兩臺遠程機器之間要通信,爲了保證安全,咱們能夠採用加密等措施,也能夠採用 SAML
來傳輸,傳輸的數據以 XML
形式,符合 SAML
規範,這樣咱們就能夠不要求兩臺機器採用什麼樣的系統,只要求能理解 SAML
規範便可,顯然比傳統的方式更好。SAML
規範是一組 Schema
定義。
能夠這麼說,在 Web Service
領域,schema
就是規範,在 Java
領域,API
就是規範
X509
認證過濾器。你能夠經過 HttpSecurity#X509()
來啓用和配置相關功能。
AbstractPreAuthenticatedProcessingFilter
處理處理通過預先認證的身份驗證請求的過濾器的基類,其中認證主體已經由外部系統進行了身份驗證。 目的只是從傳入請求中提取主體上的必要信息,而不是對它們進行身份驗證。
你能夠繼承該類進行具體實現並經過 HttpSecurity#addFilter
方法來添加個性化的AbstractPreAuthenticatedProcessingFilter
。
CAS
單點登陸認證過濾器 。依賴 Spring Security CAS 模塊
這個須要依賴 spring-scurity-oauth2
相關的模塊。OAuth2
登陸認證過濾器。處理經過 OAuth2
進行認證登陸的邏輯。
這個須要用到 Spring Security SAML
模塊,這是一個基於 SMAL
的 SSO
單點登陸認證過濾器。 關於SAML
這個看過我相關文章的應該不陌生了。處理用戶以及密碼認證的核心過濾器。認證請求提交的username
和 password
,被封裝成token
進行一系列的認證,即是主要經過這個過濾器完成的,在表單認證的方法中,這是最最關鍵的過濾器。
你能夠經過 HttpSecurity#formLogin()
及相關方法引入其配置對象 FormLoginConfigurer
來進行配置。 咱們在 Spring Security 實戰乾貨: 玩轉自定義登陸 已經對其進行過個性化的配置和魔改。
參見 3.2 ConcurrentSessionFilter 。 該過濾器可能會被屢次執行。
基於OpenID
認證協議的認證過濾器。 你須要在依賴中依賴額外的相關模塊才能啓用它。
生成默認的登陸頁。默認 /login
。
生成默認的退出頁。 默認 /logout
。
參見 3.2 ConcurrentSessionFilter 。 該過濾器可能會被屢次執行。
Digest
身份驗證是 Web
應用程序中流行的可選的身份驗證機制 。DigestAuthenticationFilter
可以處理 HTTP
頭中顯示的摘要式身份驗證憑據。你能夠經過 HttpSecurity#addFilter()
來啓用和配置相關功能。
和Digest
身份驗證同樣都是Web
應用程序中流行的可選的身份驗證機制 。 BasicAuthenticationFilter
負責處理 HTTP
頭中顯示的基自己份驗證憑據。這個 Spring Security 的 Spring Boot 自動配置默認是啓用的 。
BasicAuthenticationFilter
經過 HttpSecurity#httpBasic()
及相關方法引入其配置對象 HttpBasicConfigurer
來進行配置。
用於用戶認證成功後,從新恢復由於登陸被打斷的請求。當匿名訪問一個須要受權的資源時。會跳轉到認證處理邏輯,此時請求被緩存。在認證邏輯處理完畢後,從緩存中獲取最開始的資源請求進行再次請求。
RequestCacheAwareFilter
經過 HttpScurity#requestCache()
及相關方法引入其配置對象 RequestCacheConfigurer
來進行配置。
用來 實現j2ee
中 Servlet Api
一些接口方法, 好比 getRemoteUser
方法、isUserInRole
方法,在使用 Spring Security 時其實就是經過這個過濾器來實現的。
SecurityContextHolderAwareRequestFilter
經過 HttpSecurity.servletApi()
及相關方法引入其配置對象 ServletApiConfigurer
來進行配置。
適用於JAAS
(Java
認證受權服務)。 若是 SecurityContextHolder
中擁有的 Authentication
是一個 JaasAuthenticationToken
,那麼該 JaasApiIntegrationFilter
將使用包含在 JaasAuthenticationToken
中的 Subject
繼續執行 FilterChain
。
處理 記住我
功能的過濾器。
RememberMeAuthenticationFilter
經過 HttpSecurity.rememberMe()
及相關方法引入其配置對象 RememberMeConfigurer
來進行配置。
匿名認證過濾器。對於 Spring Security
來講,全部對資源的訪問都是有 Authentication
的。對於無需登陸(UsernamePasswordAuthenticationFilter
)直接能夠訪問的資源,會授予其匿名用戶身份。
AnonymousAuthenticationFilter
經過 HttpSecurity.anonymous()
及相關方法引入其配置對象 AnonymousConfigurer
來進行配置。
Session
管理器過濾器,內部維護了一個 SessionAuthenticationStrategy
用於管理 Session
。
SessionManagementFilter
經過 HttpScurity#sessionManagement()
及相關方法引入其配置對象 SessionManagementConfigurer
來進行配置。
主要來傳輸異常事件,還記得以前咱們見過的 DefaultAuthenticationEventPublisher
嗎?
這個過濾器決定了訪問特定路徑應該具有的權限,訪問的用戶的角色,權限是什麼?訪問的路徑須要什麼樣的角色和權限?這些判斷和處理都是由該類進行的。若是你要實現動態權限控制就必須研究該類 。
SwitchUserFilter
是用來作帳戶切換的。默認的切換帳號的url
爲/login/impersonate
,默認註銷切換帳號的url
爲/logout/impersonate
,默認的帳號參數爲username
。
你能夠經過此類實現自定義的帳戶切換。
全部內置的 31個過濾器做用都講解完了,有一些默認已經啓用。有一些須要引入特定的包而且對 HttpSecurity
進行配置纔會生效 。並且它們的順序是既定的。 只有你瞭解這些過濾器你才能基於業務深度定製 Spring Security 。
關注公衆號:Felordcn獲取更多資訊