概述
Spring Security 是一款安全管理框架,在SpringBoot/SpringCloud環境下可以達成0配置的方式集成,非常方便
大致模型
DelegatingFilterProxy
Spring提供了一個名爲DelegatingFilterProxy的過濾器實現,它允許在Servlet容器的生命週期和Spring的ApplicationContext之間架橋
FilterChainProxy
這是Spring Security提供的過濾器鏈代理,它被包含在DelegatingFilterProxy
過濾器中,在接受請求時會經由FilterChainProxy
決定來使用哪一條SecurityFilterChain
過濾器鏈
SecurityFilterChain
這個是由FilterChainProxy
代理來決定實例的調用,這樣對每一套匹配我們都可以有細緻的配置,其中SecurityFilterChain
實例下的SecurityFilter
一般都是Bean
在過濾器鏈代理對象中可以有一個或多個過濾器鏈,在多個過濾器鏈中一個請求會匹配首個滿足匹配條件的過濾器鏈
默認Chain下的Filter
- ChannelProcessingFilter:確保web請求通過通道的過濾器
- ConcurrentSessionFilter:併發會話處理包所需的過濾器,這個過濾器會進行兩個操作,一是爲每個請求設置最後一次請求事件,二是檢索回話信息檢查回話是否被標識爲已過時,如果過時則會使其失效
- WebAsyncManagerIntegrationFilter:填充
SecurityContext
的過濾器 - SecurityContextPersistenceFilter:請求處理前從
SecurityContextRepository
獲取SecurityContext
並在請求結束後清除此SecurityContext
- HeaderWriterFilter:爲請求添加一些頭部信息的過濾器
- CsrfFilter:使用同步器令牌模式應用CSRF保護,開發人員需要確保對任何允許狀態更改的請求調用
CsrfFilter
- LogoutFilter:用戶退出的過濾器,他會順序的調用
LogoutSuccessHandler
和LogoutHandler
- OAuth2AuthorizationRequestRedirectFilter:此過濾器通過將最終用戶的用戶代理重定向到授權服務器的授權端點來啓動授權代碼授予
- Saml2WebSsoAuthenticationRequestFilter:不知道是什麼用
- X509AuthenticationFilter:支持X509身份驗證的過濾器
- AbstractPreAuthenticatedProcessingFilter:預處理過濾器,對身份驗證的預先處理,默認情況下如果認證失敗任然會繼續下一個過濾器
- CasAuthenticationFilter:不知道
- OAuth2LoginAuthenticationFilter:用於OAuth 2.0登錄的過濾器實現
- Saml2WebSsoAuthenticationFilter:不知道
- UsernamePasswordAuthenticationFilter:處理表單提交的身份驗證,默認需要兩個參數(username和password)進行身份驗證,這個過濾器默認響應於請求
/login
URL的請求 - OpenIDAuthenticationFilter:處理OpenID身份驗證請求的過濾器
- DefaultLoginPageGeneratingFilter:在用戶沒有配置登錄頁面時將會插入到過濾器鏈的過濾器,提供了默認登錄頁面配置等等
- DefaultLogoutPageGeneratingFilter:構建一個默認的退出登錄頁面配置的過濾器
- DigestAuthenticationFilter:處理摘要身份驗證的處理器
- BearerTokenAuthenticationFilter:認證包含OAuth 2.0承載令牌的請求,此過濾器應該被寫入
AuthenticationManager
並BearerTokenAuthenticationToken
能被AuthenticationManager
驗證 - BasicAuthenticationFilter:基於Basic的身份驗證過濾器
- RequestCacheAwareFilter:如果緩存了一個與當前請求匹配的請求對象,負責重新構造所緩存的請求,它將會調用配置的
RequestCache
上的getMatchingRequest ()
,如果方法返回一個增強的request
則會將它交給doFilter()
,如果方法返回null
將使用原始的請求,過濾器是沒有效果的 - SecurityContextHolderAwareRequestFilter:對請求對象進行包裝增強的過濾器,這個過濾器爲請求擴展了以下幾個方法
HttpServletRequest.authenticate(HttpServletResponse)
:允許用戶確定他們是否經過身份驗證,如果沒有則將用戶發送到登錄頁面HttpServletRequest.login(String, String)
:允許用戶通過AuthenticationManager
進行身份驗證HttpServletRequest.logout()
:允許使用配置的LogoutHandler
進行註銷AsyncContext.start(Runnable)
:自動的複製從當前線程的SecurityContextHolder
找到的SecurityContext
到Runable
線程
- JaasApiIntegrationFilter:試圖獲取JAAS Subject並繼續作爲該Subject運行的過濾器
- RememberMeAuthenticationFilter:檢測
SecurityContext
中是否沒有Authentication
對象,如果RememberMeServices
有被實現,則將Authentication
填充到SecurityContext
中,通過過濾器調用RememberMeServices
的autoLogin()
方法,如果該方法返回一個非空Authentication
對象則會把此對象傳遞給AuthenticationManager
- AnonymousAuthenticationFilter:檢測
SecurityContext
中是否沒有Authentication
對象,並在需要時填充一個,默認實現是在沒有Authentication
對象時創建一個匿名的Authentication
對象放入到SecurityContext
中 - OAuth2AuthorizationCodeGrantFilter:OAuth 2.0授權代碼授予的過濾器,它處理OAuth 2.0授權響應的處理
- SessionManagementFilter:檢測用戶自請求開始以來已經通過身份驗證,如果已經通過,則調用配置的
SessionAuthenticationStrategy
來執行任何與會話相關的活動 - ExceptionTranslationFilter:處理在過濾器鏈中拋出的任何
AccessDeniedException
和AuthenticationException
異常 - FilterSecurityInterceptor:通過過濾器實現執行HTTP資源的安全處理
- SwitchUserFilter:切換用戶處理過濾器負責用戶上下文切換
Security Filters
這個是過濾器鏈中的具體過濾器,經由SecurityFilterChain
來進行註冊
Authentication 認證
Spring Security 提供了全面的身份驗證功能
以下是基於servlet應用會用到的一些組件
- SecurityContextHolder:SecurityContextHolder是Spring Security身份驗證的地方
- SecurityContext:是從
SecurityContextHolder
獲取且包含當前已認證用戶的Authentication
對象信息的組件 - Authentication:可以被輸入到
AuthenticationManager
中去提供給認證一個用戶或則認證當前用戶 - GrantedAuthority:在認證過程中授予主體(用戶)的權限組件
- AuthenticationManager:定義Spring Security的過濾器如何執行身份驗證的API
- ProviderManager:AuthenticationManager最常見的實現
- AuthenticationProvider:由ProviderManager用於執行特定類型的身份驗證
- Request Credentials with AuthenticationEntryPoint:用於從客戶端請求憑據
- AbstractAuthenticationProcessingFilter:用於身份驗證的基本過濾器
SecurityContextHolder
SecurityContextHolder
是SecurityContext
的獲取器,他可以獲取、創建SecurityContext
默認的情況下SecurityContextHolder
是使用一個ThreadLocal
來儲存這些細節,這就意味着SecurityContextHolder
只會在同一線程下的方法中可用,但我們也可以通過設置來改變這個默認模式
SecurityContext
這個SecurityContext
是從SecurityContextHolder
獲取得到的,SecurityContext
包含着Authentication
認證信息對象
Authentication
這個Authentication
主要用於以下兩個用途
- 作爲
AuthenticationManager
的輸入,提供用戶所提供的身份驗證的憑證,此時用戶是未認證的,自然isAuthenticated()
是false
- 代表當前已經認證的用戶,當前這個
Authentication
是可以通過SecurityContext
獲取得到
這個Authentication主要包含了
- principal:識別用戶,當使用用戶名/密碼進行身份驗證時,這通常是
UserDetails
的一個實例 - credentials:通常代表一個密碼,在用戶通過認證且保證不泄露的情況下通常會被清除掉
- authorities:賦予用戶的權限
GrantedAuthority
GrantedAuthority
是給用戶賦予的權限,例如角色、範圍等
GrantedAuthority
可以從Authentication.getAuthorities()
方法中獲得
AuthenticationManager
AuthenticationManager
是定義Spring Security的過濾器如何執行身份驗證的API
ProviderManager
ProviderManager
是最常用的AuthenticationManager
實現方式,ProviderManager
代表一個AuthenticationProvider
的集合,其中每一個AuthenticationProvider
都有機會去決定身份驗證是否成功、失敗、或則不下決定而交給下游的AuthenticationProvider
做決定,如果配置的AuthenticationProvider
都不能夠作出決定那麼將會拋出AuthenticationException
異常,代表不能處理這種身份驗證
在AuthenticationProvider
的集合中,每一個AuthenticationProvider
都可以處理不同類型的身份驗證,例如第一個處理的是用戶名/密碼,第二個處理的是SAML,他們互不影響
我們可以爲ProviderManager
配置一個父AuthenticationManager
,在自身沒有可處理的AuthenticationProvider
時候,將會去請求這個父AuthenticationProvider
管理器,通常這個是一個ProviderManager
實例
- 對返回的
Authentication
進行拷貝加入緩存,保留用戶憑着 - 禁用
ProviderManager
的eraseCredentialsAfterAuthentication
屬性,保留憑着
AuthenticationProvider
我們可以將多個AuthenticationProvider
注入到ProviderManager
中,每一個AuthenticationProvider
都執行特定類型的認證
AuthenticationEntryPoint
AuthenticationEntryPoint
用於發送從客戶端請求憑據的HTTP響應
AbstractAuthenticationProcessingFilter
AbstractAuthenticationProcessingFilter
是用於驗證用戶憑證的基本Filter
,在認證憑證之前,Spring Security通常使用AuthenticationEntryPoint
請求憑證
大體的執行流程
- 當用戶提交憑證,這個
AbstractAuthenticationProcessingFilter
將通過HttpServletRequest
創建一個Authentication
對象用於身份驗證,這個Authentication
的類型依賴於AbstractAuthenticationProcessingFilter
的子類 Authentication
傳遞給AuthenticationManager
進行身份驗證- 如果驗證失敗
- 這個
SecurityContextHolder
會被清除 RememberMeServices.loginFail
將會被調用,如果有配置的話AuthenticationFailureHandler
被調用
- 這個
- 如果驗證成功
SessionAuthenticationStrategy
收到新登錄的通知- 這個
Authentication
設置在SecurityContextHolder
中,隨後,SecurityContextPersistenceFilter
將SecurityContext
保存到HttpSession
RememberMeServices.loginSuccess
將被調用,如果有配置的話ApplicationEventPublisher
觸發一個InteractiveAuthenticationSuccessEvent
事件
用戶名/密碼認證
用戶名/密碼是最爲常見的身份驗證方式,Spring Security爲此提供和非常廣泛的支持
Spring Security提供了以下內置機制,用於從HttpServletRequest
讀取用戶名和密碼
表單登錄
Spring Security可以通過表單中的內容獲取登錄所需的用戶名密碼,在沒有任何配置的情況下是默認打開的,但是如果有任何servlet配置的情況下需要手動指定
protected void configure(HttpSecurity http) {
// 配置
http.formLogin(withDefaults());
}
對於默認HTML表單提交配置我們需要注意幾點:1.表單應該以post提交方式進行認證
2.表單應該指明username參數爲用戶名
2.表單應該指明password參數爲密碼
Authorization 授權
權限對象由一個GrantedAuthority
接口表示,權限對象由AuthenticationManager
插入到Authentication
對象中,然後由AccessDecisionManager s
在進行授權決策時讀取