springSecurity认证管理器

springSecurity认证管理器

​ SpringSecurity负责验证用户身份需要用到认证管理器(AuthenticationManager)。

认证管理器的接口很简单,只有一个方法,将用户名密码传入此认证器,如果不报错则为认证通过。

1
2
3
4
public interface AuthenticationManager {
Authentication authenticate(Authentication authentication)
throws AuthenticationException;
}

认证管理器

​ 在springSecurity里,我们可以配置多个认证管理器,将多个认证管理器合并成一个ProviderManager对外提供服务,只要有一个认证管理器认证通过,则表示通过,是一种责任链模式。

image-20200720125330662

​ 将多个authenticationProviders合并成一个的代码实现在这里

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder#performBuild 	
@Override
protected ProviderManager performBuild() throws Exception {
//将多个authenticationProviders合并成一个
ProviderManager providerManager = new ProviderManager(authenticationProviders,
parentAuthenticationManager);
//验证通过是否擦除密码
if (eraseCredentials != null) {
providerManager.setEraseCredentialsAfterAuthentication(eraseCredentials);
}
if (eventPublisher != null) {
providerManager.setAuthenticationEventPublisher(eventPublisher);
}
providerManager = postProcess(providerManager);
return providerManager;
}

配置认证管理器

配置的方式有两种,一种是重写下面的方法,配置好userDetailServicepasswoedEncoder

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(new UserDetailsService() {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//此处从数据库加载用户信息,并构造出userDetail的实例返回
return null;
}
}).passwordEncoder(new PasswordEncoder() {
@Override
public String encode(CharSequence rawPassword) {
return null;
}

//验证前传入的密码和数据库里的密码是否正确
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return false;
}
});

}

上面的代码则会自动配置一个DaoAuthentication

​ 另一种方式是将userDetailServicepasswordEncoder 配置成spring的bean,框架就能自动查找到。

具体实现请查看在@EnableGlobalAuthentication注解是如何做的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
//配置初始化userDetail的配置
@Bean
public static InitializeUserDetailsBeanManagerConfigurer initializeUserDetailsBeanManagerConfigurer(ApplicationContext context) {
return new InitializeUserDetailsBeanManagerConfigurer(context);
}

//配置会被自动注入进来
@Autowired(required = false)
public void setGlobalAuthenticationConfigurers(
List<GlobalAuthenticationConfigurerAdapter> configurers) {
configurers.sort(AnnotationAwareOrderComparator.INSTANCE);
this.globalAuthConfigurers = configurers;
}

//配置内部的实现
class InitializeUserDetailsManagerConfigurer
extends GlobalAuthenticationConfigurerAdapter {
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
if (auth.isConfigured()) {
return;
}
//从容器内获取UserDetailsService
UserDetailsService userDetailsService = getBeanOrNull(
UserDetailsService.class);
if (userDetailsService == null) {
return;
}
//从容器内获取PasswordEncoder
PasswordEncoder passwordEncoder = getBeanOrNull(PasswordEncoder.class);
UserDetailsPasswordService passwordManager = getBeanOrNull(UserDetailsPasswordService.class);

//创建DaoAuthenticationProvider
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService);
if (passwordEncoder != null) {
provider.setPasswordEncoder(passwordEncoder);
}
if (passwordManager != null) {
provider.setUserDetailsPasswordService(passwordManager);
}
provider.afterPropertiesSet();

auth.authenticationProvider(provider);
}


​ 上面两种配置方式都是可以的,本人更推荐第一种方式。一方面代码几种在一个配置文件里,比较方便查找,一方面如果想配置多个HttpSecurity,每个有独立的UserDetailService也更方便。

框架对两种配置方式如何选择的

​ 查看代码

1
org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#authenticationManager

​ 通过configure方法重写,如果没重写则为自动配置,重写了就是手动配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
protected AuthenticationManager authenticationManager() throws Exception {
//如果没初始化则初始化
if (!authenticationManagerInitialized) {
//默认将disableLocalConfigureAuthenticationBldr设置true
configure(localConfigureAuthenticationBldr);
//使用本地自定义配置,就是配置1
if (disableLocalConfigureAuthenticationBldr) {
authenticationManager = authenticationConfiguration
.getAuthenticationManager();
}
//使用自动配置,配置2
else {
authenticationManager = localConfigureAuthenticationBldr.build();
}
authenticationManagerInitialized = true;
}
return authenticationManager;
}

protected void configure(AuthenticationManagerBuilder auth) throws Exception {
this.disableLocalConfigureAuthenticationBldr = true;
}

springSecurity认证管理器
https://www.huangchaoyu.com/4256921896.html
作者
hcy
发布于
2020年7月20日
更新于
2024年8月17日
许可协议