Spring Security驗證流程剖析及自定義驗證方法

Spring Security本質上是一連串的Filter, 而後又以一個獨立的Filter的形式插入到Filter Chain裏,其名爲FilterChainProxy。 如圖所示。java

實際上FilterChainProxy下面能夠有多條Filter Chain,來針對不一樣的URL作驗證,而Filter Chain中所擁有的Filter則會根據定義的服務自動增減。因此無須要顯示再定義這些Filter,除非想要實現本身的邏輯。ide

關鍵類

Authentication

Authentication是一個接口,用來表示用戶認證信息,在用戶登陸認證以前相關信息會封裝爲一個Authentication具體實現類的對象,在登陸認證成功以後又會生成一個信息更全面,包含用戶權限等信息的Authentication對象,而後把它保存在 SecurityContextHolder所持有的SecurityContext中,供後續的程序進行調用,如訪問權限的鑑定等。ui

AuthenticationManager

用來作驗證的最主要的接口爲AuthenticationManager,這個接口只有一個方法:spa

public interface AuthenticationManager { Authentication authenticate(Authentication authentication) throws AuthenticationException; }

其中authenticate()方法運行後可能會有三種狀況:3d

  1. 驗證成功,返回一個帶有用戶信息的Authentication
  2. 驗證失敗,拋出一個AuthenticationException異常。
  3. 沒法判斷,返回null

ProviderManager

ProviderManager是上面的AuthenticationManager最多見的實現,它不本身處理驗證,而是將驗證委託給其所配置的AuthenticationProvider列表,而後會依次調用每個 AuthenticationProvider進行認證,這個過程當中只要有一個AuthenticationProvider驗證成功,就不會再繼續作更多驗證,會直接以該認證結果做爲ProviderManager的認證結果。code

認證過程

  1. 用戶使用用戶名和密碼進行登陸。
  2. Spring Security將獲取到的用戶名和密碼封裝成一個Authentication接口的實現類,好比經常使用的UsernamePasswordAuthenticationToken
  3. 將上述產生的Authentication對象傳遞給AuthenticationManager的實現類ProviderManager進行認證。
  4. ProviderManager依次調用各個AuthenticationProvider進行認證,認證成功後返回一個封裝了用戶權限等信息的Authentication對象。
  5. AuthenticationManager返回的Authentication對象賦予給當前的SecurityContext

自定義驗證

有了以上的知識儲備後就能夠來自定義驗證方法了。經過上面能夠看出,實際上真正來作驗證操做的是一個個的AuthenticationProvider,因此若是要自定義驗證方法,只須要實現一個本身的AuthenticationProvider而後再將其添加進ProviderManager裏就好了。對象

自定義AuthenticationProvider

@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

如今再將剛建立的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(); } }
相關文章
相關標籤/搜索