Spring Security 實戰乾貨:AuthenticationManager的初始化細節
阿新 • • 發佈:2021-01-25
![](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