1. 程式人生 > >Spring Security 實戰乾貨:AuthenticationManager的初始化細節

Spring Security 實戰乾貨:AuthenticationManager的初始化細節

![](https://img2020.cnblogs.com/other/1739473/202101/1739473-20210125143721661-115930443.jpg) ## 1. 前言 今天有個同學告訴我,在**Security Learning**專案的**day11**分支中出現了一個問題,驗證碼登入和其它登入不相容了,出現了**No Provider**異常。還有這事?我趕緊跑了一遍還真是,看來我大意了,不過最終找到了原因,問題就出在`AuthenticationManager`的初始化上。自定義了一個`UseDetailService`和`AuthenticationProvider`之後`AuthenticationManager`的預設初始化出問題了。 雖然在[Spring Security 實戰乾貨:圖解認證管理器AuthenticationManager](https://felord.cn/authenticationManager.html)一文中對`AuthenticationManager`的流程進行了分析,但是還是不夠深入,以至於出現了問題。今天就把這個坑補了。 ## 2. AuthenticationManager的初始化 關於`AuthenticationManager`的初始化,流程部分請看這一篇[文章](https://felord.cn/authenticationManager.html),裡面有流程圖。在流程圖中我們提到了`AuthenticationManager`的預設初始化是由`AuthenticationConfiguration`完成的,但是隻是一筆帶過,具體的細節沒有搞清楚。現在就搞定它。 ### AuthenticationConfiguration `AuthenticationConfiguration`初始化`AuthenticationManager`的核心方法就是下面這個方法: ```java public AuthenticationManager getAuthenticationManager() throws Exception { // 先判斷 AuthenticationManager 是否初始化 if (this.authenticationManagerInitialized) { // 如果已經初始化 那麼直接返回初始化的 return this.authenticationManager; } // 否則就去 Spring IoC 中獲取其構建類 AuthenticationManagerBuilder authBuilder = this.applicationContext.getBean(AuthenticationManagerBuilder.class); // 如果不是第一次構建 好像是每次總要通過Builder來進行構建 if (this.buildingAuthenticationManager.getAndSet(true)) { // 返回 一個委託的AuthenticationManager return new AuthenticationManagerDelegator(authBuilder); } // 如果是第一次通過Builder構建 將全域性的認證配置整合到Builder中 那麼以後就不用再整合全域性的配置了 for (GlobalAuthenticationConfigurerAdapter config : globalAuthConfigurers) { authBuilder.apply(config); } // 構建AuthenticationManager authenticationManager = authBuilder.build(); // 如果構建結果為null if (authenticationManager == null) { // 再次嘗試去Spring IoC 獲取懶載入的 AuthenticationManager Bean authenticationManager = getAuthenticationManagerBean(); } // 修改初始化狀態 this.authenticationManagerInitialized = true; return authenticationManager; } ``` 根據上面的註釋,`AuthenticationManager`的初始化流程是清楚的。但是又引出來了兩個問題,我將另起兩個章節來分析這兩個問題。 ### AuthenticationManagerBuilder > 第一個問題是`AuthenticationManagerBuilder`是如何注入**Spring IoC**的? `AuthenticationManagerBuilder`注入的過程也是在`AuthenticationConfiguration`中完成的,注入的是其內部的一個靜態類`DefaultPasswordEncoderAuthenticationManagerBuilder`,這個類和Spring Security的主配置類`WebSecurityConfigurerAdapter`的一個內部類同名,這兩個類幾乎邏輯相同,沒有什麼特別的。具體使用哪個由`WebSecurityConfigurerAdapter.disableLocalConfigureAuthenticationBldr`決定。 > 其引數`ObjectPostP