咱們上一篇介紹了UsernamePasswordAuthenticationFilter
的工做流程,留下了一個小小的伏筆,做爲一個Servlet Filter應該存在一個doFilter
實現方法,而它卻沒有,其實它的父類AbstractAuthenticationProcessingFilter
提供了具體的實現。稍後咱們會根據這個實現引出今天的主角AuthenticationManager
,來繼續介紹用戶的認證過程。html
咱們來看看AbstractAuthenticationProcessingFilter
的核心方法doFilter
的實現:java
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; // 先經過請求的uri來判斷是否須要認證,好比默認的/login if (!requiresAuthentication(request, response)) { chain.doFilter(request, response); return; } if (logger.isDebugEnabled()) { logger.debug("Request is to process authentication"); } Authentication authResult; try { // 接着就是執行子類鉤子方法attemptAuthentication來獲取認證結果對象Authentication ,這個對象不能是空 不然直接返回 authResult = attemptAuthentication(request, response); if (authResult == null) { // return immediately as subclass has indicated that it hasn't completed // authentication return; } // 處理session 策略,這裏默認沒有任何策略 sessionStrategy.onAuthentication(authResult, request, response); } catch (InternalAuthenticationServiceException failed) { logger.error( "An internal error occurred while trying to authenticate the user.", failed); // 若是遇到異常 就會交給認證失敗處理器 AuthenticationFailureHandler 來處理 unsuccessfulAuthentication(request, response, failed); return; } catch (AuthenticationException failed) { // Authentication failed unsuccessfulAuthentication(request, response, failed); return; } // 認證成功後繼續其它過濾器鏈 並最終交給認證成功處理器 AuthenticationSuccessHandler 處理 if (continueChainBeforeSuccessfulAuthentication) { chain.doFilter(request, response); } successfulAuthentication(request, response, chain, authResult); }
大部分邏輯這裏是清晰的,關鍵在於attemptAuthentication
方法,這個咱們已經在上一文分析了是經過AuthenticationManager
的authenticate
方法進行認證邏輯的處理,接下來咱們將重點分析這個接口來幫助咱們瞭解Spring Seucirty的認證過程。spring
AuthenticationManager
這個接口方法很是奇特,入參和返回值的類型都是Authentication
。該接口的做用是對用戶的未授信憑據進行認證,認證經過則返回授信狀態的憑據,不然將拋出認證異常AuthenticationException
。session
那麼AbstractAuthenticationProcessingFilter
中的 AuthenticationManager
是在哪裏配置的呢? 看過Spring Security 實戰乾貨系列應該知道WebSecurityConfigurerAdapter
中的void configure(AuthenticationManagerBuilder auth)
是配置AuthenticationManager
的地方, 我根據源碼總結了一下AuthenticationManager
的初始化流程,相信能夠幫助你去閱讀相關的源碼:ide
須要注意的是若是咱們使用自定義配置必定不能按照相似下面的錯誤示範:ui
@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider(); daoAuthenticationProvider.setUserDetailsService(weChatSecurityConfigProperties.getUserDetailsService()); daoAuthenticationProvider.setPasswordEncoder(multiPasswordEncoder()); auth.authenticationProvider(daoAuthenticationProvider); // 調用 super 將致使不生效 因此下面語句不要寫 super.configure(auth); }
AuthenticationManager
的實現ProviderManager
管理了衆多的AuthenticationProvider
。每個AuthenticationProvider
都只支持特定類型的Authentication
,若是不支持將會跳過。另外一個做用就是對適配的Authentication
進行認證,只要有一個認證成功,那麼就認爲認證成功,全部的都沒有經過才認爲是認證失敗。認證成功後的Authentication
就變成授信憑據,並觸發認證成功的事件。認證失敗的就拋出異常觸發認證失敗的事件。spa
從這裏咱們能夠看出認證管理器AuthenticationManager
針對特定的Authentication
提供了特定的認證功能,咱們能夠藉此來實現多種認證並存。debug
經過本文咱們對Spring Security認證管理器AuthenticationManager
的初始化過程和認證過程進行了分析,若是你熟悉了AuthenticationManager
的邏輯能夠實現多種認證方式的並存等能力,實現不少有用的邏輯,這對集成Spring Security到項目中很是重要。多多關注:碼農小胖哥 獲取更多的原創乾貨。code
關注公衆號:Felordcn 獲取更多資訊
htm