1. 前言
我們上一篇介紹了UsernamePasswordAuthenticationFilter的作業流程,留下了一個小小的伏筆,作為一個Servlet Filter應該存在一個doFilter實作方法,而它卻沒有,其實它的父類AbstractAuthenticationProcessingFilter提供了具體的實作,稍后我們會根據這個實作引出今天的主角AuthenticationManager,來繼續介紹用戶的認證程序,
2. AbstractAuthenticationProcessingFilter
我們來看看AbstractAuthenticationProcessingFilter的核心方法doFilter的實作:
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的認證程序,
3. AuthenticationManager
AuthenticationManager這個介面方法非常奇特,入參和回傳值的型別都是Authentication,該介面的作用是對用戶的未授信憑據進行認證,認證通過則回傳授信狀態的憑據,否則將拋出認證例外AuthenticationException,
3.1 AuthenticationManager的初始化流程
那么AbstractAuthenticationProcessingFilter中的 AuthenticationManager 是在哪里配置的呢? 看過Spring Security 實戰干貨系列應該知道WebSecurityConfigurerAdapter中的void configure(AuthenticationManagerBuilder auth)是配置AuthenticationManager 的地方, 我根據原始碼總結了一下AuthenticationManager 的初始化流程,相信可以幫助你去閱讀相關的原始碼:

需要注意的是如果我們使用自定義配置一定不能按照類似下面的錯誤示范:
@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);
}
3.2 AuthenticationManager的認證程序
AuthenticationManager的實作ProviderManager管理了眾多的AuthenticationProvider,每一個AuthenticationProvider都只支持特定型別的Authentication,如果不支持將會跳過,另一個作用就是對適配的Authentication進行認證,只要有一個認證成功,那么就認為認證成功,所有的都沒有通過才認為是認證失敗,認證成功后的Authentication就變成授信憑據,并觸發認證成功的事件,認證失敗的就拋出例外觸發認證失敗的事件,

從這里我們可以看出認證管理器AuthenticationManager針對特定的Authentication提供了特定的認證功能,我們可以借此來實作多種認證并存,
4. 總結
通過本文我們對Spring Security認證管理器AuthenticationManager的初始化程序和認證程序進行了分析,如果你熟悉了AuthenticationManager的邏輯可以實作多種認證方式的并存等能力,實作很多有用的邏輯,這對集成Spring Security到專案中非常重要,多多關注:碼農小胖哥 獲取更多的原創干貨,
關注公眾號:Felordcn 獲取更多資訊
個人博客:https://felord.cn
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/137122.html
標籤:Java
