Spring Security
本質上是一連串的Filter
, 而後又以一個獨立的Filter
的形式插入到Filter Chain
裏,其名爲FilterChainProxy
。 如圖所示。java
實際上FilterChainProxy
下面能夠有多條Filter Chain
,來針對不一樣的URL作驗證,而Filter Chain
中所擁有的Filter
則會根據定義的服務自動增減。因此無須要顯示再定義這些Filter
,除非想要實現本身的邏輯。ide
Authentication
是一個接口,用來表示用戶認證信息,在用戶登陸認證以前相關信息會封裝爲一個Authentication
具體實現類的對象,在登陸認證成功以後又會生成一個信息更全面,包含用戶權限等信息的Authentication
對象,而後把它保存在 SecurityContextHolder
所持有的SecurityContext
中,供後續的程序進行調用,如訪問權限的鑑定等。ui
用來作驗證的最主要的接口爲AuthenticationManager
,這個接口只有一個方法:spa
public interface AuthenticationManager { Authentication authenticate(Authentication authentication) throws AuthenticationException; }
其中authenticate()
方法運行後可能會有三種狀況:3d
Authentication
。AuthenticationException
異常。null
。ProviderManager
是上面的AuthenticationManager
最多見的實現,它不本身處理驗證,而是將驗證委託給其所配置的AuthenticationProvider
列表,而後會依次調用每個 AuthenticationProvider
進行認證,這個過程當中只要有一個AuthenticationProvider
驗證成功,就不會再繼續作更多驗證,會直接以該認證結果做爲ProviderManager
的認證結果。code
Spring Security
將獲取到的用戶名和密碼封裝成一個Authentication
接口的實現類,好比經常使用的UsernamePasswordAuthenticationToken
。Authentication
對象傳遞給AuthenticationManager
的實現類ProviderManager
進行認證。ProviderManager
依次調用各個AuthenticationProvider
進行認證,認證成功後返回一個封裝了用戶權限等信息的Authentication
對象。AuthenticationManager
返回的Authentication
對象賦予給當前的SecurityContext
。有了以上的知識儲備後就能夠來自定義驗證方法了。經過上面能夠看出,實際上真正來作驗證操做的是一個個的AuthenticationProvider
,因此若是要自定義驗證方法,只須要實現一個本身的AuthenticationProvider
而後再將其添加進ProviderManager
裏就好了。對象
@Component public class CustomAuthenticationProvider implements AuthenticationProvider { @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { String name = authentication.getName(); String password = authentication.getCredentials().toString(); if (shouldAuthenticateAgainstThirdPartySystem()) { // use the credentials // and authenticate against the third-party system return new UsernamePasswordAuthenticationToken( name, password, new ArrayList<>()); } else { return null; } } @Override public boolean supports(Class<?> authentication) { return authentication.equals( UsernamePasswordAuthenticationToken.class); } }
其中的supports()
方法接受一個authentication
參數,用來判斷傳進來的authentication
是否是該AuthenticationProvider
可以處理的類型。blog
如今再將剛建立的AuthenticationProvider
在與ProviderManager
裏註冊,全部操做就完成了。接口
@Configuration @EnableWebSecurity @ComponentScan("org.baeldung.security") public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private CustomAuthenticationProvider authProvider; @Override protected void configure( AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(authProvider); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().anyRequest().authenticated() .and() .httpBasic(); } }