投票传送门
1. 前言
今天有个同学告诉我,在
Security Learning
项目的
day11
分支中出现了一个问题,验证码登录和其它登录不兼容了,出现了
No Provider
异常。还有这事?我赶紧跑了一遍还真是,看来我大意了,不过最终找到了原因,问题就出在
AuthenticationManager
的初始化上。自定义了一个
UseDetailService
和
AuthenticationProvider
之后
AuthenticationManager
的默认初始化出问题了。
虽然在
Spring Security 实战干货:图解认证管理器AuthenticationManager
一文中对
AuthenticationManager
的流程进行了分析,但是还是不够深入,以至于出现了问题。今天就把这个坑补了。
2. AuthenticationManager的初始化
关于
AuthenticationManager
的初始化,流程部分请看这一篇
文章
,里面有流程图。在流程图中我们提到了
AuthenticationManager
的默认初始化是由
AuthenticationConfiguration
完成的,但是只是一笔带过,具体的细节没有搞清楚。现在就搞定它。
AuthenticationConfiguration
AuthenticationConfiguration
初始化
AuthenticationManager
的核心方法就是下面这个方法:
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;
}
复制代码