Spring Security是一個Java框架,用於保護應用程式的安全性。它提供了一套全面的安全解決方案,包括身份驗證、授權、防止攻擊等功能。Spring Security基於過濾器鏈的概念,可以輕鬆地集成到任何基於Spring的應用程式中。它支持多種身份驗證選項和授權策略,開發人員可以根據需要選... ...
什麼是SpringSecurity
Spring Security是一個Java框架,用於保護應用程式的安全性。它提供了一套全面的安全解決方案,包括身份驗證、授權、防止攻擊等功能。Spring Security基於過濾器鏈的概念,可以輕鬆地集成到任何基於Spring的應用程式中。它支持多種身份驗證選項和授權策略,開發人員可以根據需要選擇適合的方式。此外,Spring Security還提供了一些附加功能,如集成第三方身份驗證提供商和單點登錄,以及會話管理和密碼編碼等。
Spring Security是一個強大且易於使用的框架,可以幫助開發人員提高應用程式的安全性和可靠性。而我們最常用的兩個功能就是認證和鑒權,因此作為入門文章本文也只介紹這兩個功能的使用。
❝Spring Security可以用於Servlet應用和Reactive應用,本文主要介紹基於Servlet應用的場景
❞
如需更詳細的使用方式請參考官方文檔:https://spring.io/projects/spring-security
架構
上圖是Spring Security官方提供的架構圖。我們先看圖的左邊部分,就是一個典型Servlet
Filter
(過濾器)處理流程,我們依次講解流程涉及的組件。
FilterChain
FilterChain
:過濾器鏈,是Servlet
容器在接收到客戶端發送的請求時創建的,一個FilterChain
可以包含多個Filter
和一個Servlet
,Servlet
容器根據請求URI的路徑來處理HttpServletRequest
。
在Spring MVC中,Servlet
就是 DispatcherServlet
實例。一個 Servlet
最多只能處理一個 HttpServletRequest
和 HttpServletResponse
。然而,可以使用多個 Filter
來完成如下工作。
防止下游的 Filter
或Servlet
被調用。在這種阻斷請求的情況下,Filter
通常會使用HttpServletResponse
對客戶端寫入響應內容。修改下游的 Filter
和Servlet
所使用的HttpServletRequest
或HttpServletResponse
。
DelegatingFilterProxy
DelegatingFilterProxy
:Spring Security 對 Servlet
的支持是基於Servlet
Filter
的,而DelegatingFilterProxy
就是Spring Security的Filter
實現。
DelegatingFilterProxy
允許在 Servlet
容器的生命周期和 Spring 的 ApplicationContext
之間建立橋梁。Servlet
容器允許通過使用自己的標準來註冊 Filter
實例,但Servlet
容器不知道 Spring 定義的 Bean。因此大多數情況下我們通過標準的Servlet
容器機制來註冊 DelegatingFilterProxy
,但將所有工作委托給實現 Filter
的Spring Bean。
❝Spring Security會自動向
❞Servlet
容器機制註冊DelegatingFilterProxy
,無需我們手動去註冊
FilterChainProxy
FilterChainProxy
:是 Spring Security 提供的一個特殊的 Filter
,允許通過 SecurityFilterChain
委托給許多 Filter
實例。由於 FilterChainProxy
是一個Spring Bean,因此它被包含在 DelegatingFilterProxy
中。
SecurityFilterChain
SecurityFilterChain
:是FilterChainProxy
用來確定當前請求應該調用哪些Spring Security Filter
實例的過濾器鏈。
SecurityFilterChain
中的 Security
Filter
一般都是Spring Bean,但這些Security
Filter
是用 FilterChainProxy
進行註冊,而不是通過DelegatingFilterProxy
註冊。與直接向Servlet容器或 DelegatingFilterProxy
註冊相比,FilterChainProxy
有很多優勢。
首先,由於 FilterChainProxy
是 Spring Security 使用的核心,它可以處理一些必須要做的事情。 例如:清除 SecurityContext
以避免記憶體泄漏。應用Spring Security的 HttpFirewall
來保護應用程式免受某些類型的攻擊。
其次,它在確定何時應該調用 SecurityFilterChain
方面提供了更大的靈活性。在Servlet容器中,Filter
實例僅基於URL被調用。 然而,FilterChainProxy
可以通過使用RequestMatcher
介面,根據HttpServletRequest
中的任何內容確定調用。
圖的右邊部分是存在多個SecurityFilterChain
, FilterChainProxy
的匹配策略則是匹配第一個滿足的 SecurityFilterChain
。
比如,請求的URL是 /api/messages/
,它首先與 /api/**
的 SecurityFilterChain 0
模式匹配,所以只有 SecurityFilterChain0
被調用;雖然它也與 SecurityFilterChain n
匹配。
如果請求的URL是 /messages/
,它與 /api/**
的 SecurityFilterChain 0
模式不匹配,所以 FilterChainProxy
繼續嘗試每個 SecurityFilterChain
。如果沒有其他 SecurityFilterChain
實例相匹配,則調用 SecurityFilterChain n
。
SecurityFilter
SecurityFilter
:是指通過SecurityFilterChain
插入 FilterChainProxy
中的 Filter
。
這些 Filter
可以用於許多不同的目的,如 認證、 授權、 漏洞保護等。Filter
是按照特定的順序執行的,以保證它們在正確的時間被調用。
例如,執行認證的 Filter
應該在執行授權的 Filter
之前被調用。如果想要知道 Spring Security 的 Filter
的順序,可以查看 FilterOrderRegistration
源碼。
❝如果想查看你應用中註冊了哪些
❞SecurityFilter
的話可以將org.springframework.security的日誌級別調到info,這樣在你應用啟動的時候就會在控制台列印出當前應用註冊的所有SecurityFilter
。效果如下:
2023-06-14T08:55:22.321-03:00 INFO 76975 --- [ main] o.s.s.web.DefaultSecurityFilterChain : Will secure any request with [
org.springframework.security.web.session.DisableEncodeUrlFilter@404db674,
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@50f097b5,
org.springframework.security.web.context.SecurityContextHolderFilter@6fc6deb7,
org.springframework.security.web.header.HeaderWriterFilter@6f76c2cc,
org.springframework.security.web.csrf.CsrfFilter@c29fe36,
org.springframework.security.web.authentication.logout.LogoutFilter@ef60710,
org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@7c2dfa2,
org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@4397a639,
org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@7add838c,
org.springframework.security.web.authentication.www.BasicAuthenticationFilter@5cc9d3d0,
org.springframework.security.web.savedrequest.RequestCacheAwareFilter@7da39774,
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@32b0876c,
org.springframework.security.web.authentication.AnonymousAuthenticationFilter@3662bdff,
org.springframework.security.web.access.ExceptionTranslationFilter@77681ce4,
org.springframework.security.web.access.intercept.AuthorizationFilter@169268a7]
至此,Spring Security官方架構圖中涉及的組件就基本介紹完了,大家先對整體架構和執行流程有一個瞭解,只有先瞭解了整體架構,才方便接下來我們去理解Spring Security是如何去實現認證和授權的。
常用Spring Security開啟的SecurityFilter
CsrfFilter:防止Csrf攻擊的 SecurityFilter
AuthorizationFilter:授權 SecurityFilter
ExceptionTranslationFilter:處理認證和授權異常的 SecurityFilter
異常處理
Spring Security中有一個ExceptionTranslationFilter
,ExceptionTranslationFilter
作為 Security Filter 之一被插入到 FilterChainProxy 中。
ExceptionTranslationFilter
可以處理AuthenticationException或AccessDeniedException,其邏輯大概是這樣:
try {
filterChain.doFilter(request, response);
} catch (AccessDeniedException | AuthenticationException ex) {
if (!authenticated || ex instanceof AuthenticationException) {
startAuthentication();
} else {
accessDenied();
}
}
❝這段代碼的邏輯大致就是,攔截AccessDeniedException 或 AuthenticationException,如果不是這兩個異常則不處理。
❞
ExceptionTranslationFilter
流程如下:
因此如果我們想自己處理AuthenticationException或者AccessDeniedException,分別實現AuthenticationEntryPoint
或者AccessDeniedHandler
即可
@Component