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

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

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

關鍵類

Authentication

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

AuthenticationManager

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

public interface AuthenticationManager {

  Authentication authenticate(Authentication authentication)
    throws AuthenticationException;

}

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

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

ProviderManager

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

認證過程

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

自定義驗證

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

自定義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可以處理的類型。接口

註冊AuthenticationProvider

如今再將剛建立的AuthenticationProvider與ProviderManager裏註冊,全部操做就完成了。get

@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();
    }
}

參考資料it

  1. Spring Security Architecture
  2. Spring Security Authentication Provider
  3. Spring Security 簡介系列
相關文章
相關標籤/搜索