前篇:Spring Security源码学习——建造者基础架构
前言
在 Spring Security 中,用来处理身份认证的类是 AuthenticationManager,我们也称之为认证管理器。
AuthenticationManager 中规范了 Spring Security 的过滤器要如何执行身份认证,并在身份认证成功后返回一个经过认证的 Authentication 对象。AuthenticationManager 是一个接口,我们可以自定义它的实现,但是通常我们使用更多的是系统提供的 ProviderManager。
一、源码分析
public class AuthenticationManagerBuilder // 忽略代码 ............... {
private AuthenticationManager parentAuthenticationManager; //认证器
private List<AuthenticationProvider> authenticationProviders = new ArrayList<>(); //认证生成器池
private UserDetailsService defaultUserDetailsService;//用户信息
private Boolean eraseCredentials;
private AuthenticationEventPublisher eventPublisher;//认证事件发布器
//忽略代码。。。。。。。。。。
public AuthenticationManagerBuilder eraseCredentials(boolean eraseCredentials) {
this.eraseCredentials = eraseCredentials;
return this;
}
@Override
protected ProviderManager performBuild() throws Exception {
if (!isConfigured()) {
logger.debug("No authenticationProviders and no parentAuthenticationManager defined. Returning null.");
return null;
}
ProviderManager providerManager = new ProviderManager(authenticationProviders,parentAuthenticationManager);
if (eraseCredentials != null) {
providerManager.setEraseCredentialsAfterAuthentication(eraseCredentials);
}
if (eventPublisher != null) {
providerManager.setAuthenticationEventPublisher(eventPublisher);
}
providerManager = postProcess(providerManager);
return providerManager;
}
}
AuthenticationManagerBuilder方法可以分为2中,一种是设置,另一种是获取
1.1 设置AuthenticationManager
public AuthenticationManagerBuilder parentAuthenticationManager(AuthenticationManager authenticationManager) {
if (authenticationManager instanceof ProviderManager) {
eraseCredentials(((ProviderManager) authenticationManager).isEraseCredentialsAfterAuthentication());
}
this.parentAuthenticationManager = authenticationManager;
return this;
}
1.2 设置AuthenticationEventPublisher
public AuthenticationManagerBuilder authenticationEventPublisher(AuthenticationEventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
return this;
}
1.3 设置AuthenticationProvider
public AuthenticationManagerBuilder authenticationProvider(AuthenticationProvider authenticationProvider) {
this.authenticationProviders.add(authenticationProvider);
return this;
}
1.4 获取JdbcUserDetailsManagerConfigurer
public JdbcUserDetailsManagerConfigurer<AuthenticationManagerBuilder> jdbcAuthentication()// .. {
return apply(new JdbcUserDetailsManagerConfigurer<>());
}
1.5 获取DaoAuthenticationConfigurer
public <T extends UserDetailsService> DaoAuthenticationConfigurer<AuthenticationManagerBuilder, T> userDetailsService(T userDetailsService) // .. {
this.defaultUserDetailsService = userDetailsService;
return apply(new DaoAuthenticationConfigurer<>(userDetailsService));
}
1.6 获取InMemoryUserDetailsManagerConfigurer
public InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder> inMemoryAuthentication() // ..{
return apply(new InMemoryUserDetailsManagerConfigurer<>());
}
1.7 获取LdapAuthenticationProviderConfigurer
public LdapAuthenticationProviderConfigurer<AuthenticationManagerBuilder> ldapAuthentication()// ..{
return apply(new LdapAuthenticationProviderConfigurer<>());
}
1.8 获取UserDetailsService
public UserDetailsService getDefaultUserDetailsService() {
return this.defaultUserDetailsService;
}
二、AuthenticationManagerBuilder的初始化
```java
@Configuration(proxyBeanMethods = false)
@Import(ObjectPostProcessorConfiguration.class)
public class AuthenticationConfiguration {
private AtomicBoolean buildingAuthenticationManager = new AtomicBoolean();
private ApplicationContext applicationContext;
private AuthenticationManager authenticationManager;
private boolean authenticationManagerInitialized;
private List<GlobalAuthenticationConfigurerAdapter> globalAuthConfigurers = Collections
.emptyList();
//通过@Autowired标注setObjectPostProcessor方法,获取容器中的ObjectPostProcessor,然后复制给objectPostProcessor
private ObjectPostProcessor<Object> objectPostProcessor;
@Bean
public AuthenticationManagerBuilder authenticationManagerBuilder( ObjectPostProcessor<Object> objectPostProcessor, ApplicationContext context) {
LazyPasswordEncoder defaultPasswordEncoder = new LazyPasswordEncoder(context);
//从容器中创建并获取AuthenticationEventPublisher
AuthenticationEventPublisher authenticationEventPublisher = getBeanOrNull(context, AuthenticationEventPublisher.class);
DefaultPasswordEncoderAuthenticationManagerBuilder result = new DefaultPasswordEncoderAuthenticationManagerBuilder(objectPostProcessor, defaultPasswordEncoder);
if (authenticationEventPublisher != null) {
result.authenticationEventPublisher(authenticationEventPublisher);
}
return result;
}
}
默认PasswordEncoder是DelegatingPasswordEncoder
LazyPasswordEncoder的作用是延迟真正PasswordEncoder的加载,让PasswordEncoder在使时加载,真正PasswordEncoder是其属性passwordEncoder
@Configuration(proxyBeanMethods = false)
@Import(ObjectPostProcessorConfiguration.class)
public class AuthenticationConfiguration {
static class LazyPasswordEncoder implements PasswordEncoder {
private ApplicationContext applicationContext;
private PasswordEncoder passwordEncoder;
//在调用过程中LazyPasswordEncoder
@Override
public String encode(CharSequence rawPassword) {
return getPasswordEncoder().encode(rawPassword);
}
@Override
public boolean matches(CharSequence rawPassword,
String encodedPassword) {
return getPasswordEncoder().matches(rawPassword, encodedPassword);
}
@Override
public boolean upgradeEncoding(String encodedPassword) {
return getPasswordEncoder().upgradeEncoding(encodedPassword);
}
private PasswordEncoder getPasswordEncoder() {
if (this.passwordEncoder != null) {
return this.passwordEncoder;
}
//获取容器中的PasswordEncoder
PasswordEncoder passwordEncoder = getBeanOrNull(this.applicationContext, PasswordEncoder.class);
if (passwordEncoder == null) {
//如果没有默认创建DelegatingPasswordEncoder
passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
this.passwordEncoder = passwordEncoder;
return passwordEncoder;
}
@Override
public String toString() {
return getPasswordEncoder().toString();
}
}
}
默认创建DelegatingPasswordEncoder的代码如下
public class PasswordEncoderFactories {
@SuppressWarnings("deprecation")
public static PasswordEncoder createDelegatingPasswordEncoder() {
String encodingId = "bcrypt";
Map<String, PasswordEncoder> encoders = new HashMap<>();
encoders.put(encodingId, new BCryptPasswordEncoder());
encoders.put("ldap", new org.springframework.security.crypto.password.LdapShaPasswordEncoder());
encoders.put("MD4", new org.springframework.security.crypto.password.Md4PasswordEncoder());
encoders.put("MD5", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("MD5"));
encoders.put("noop", org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance());
encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
encoders.put("scrypt", new SCryptPasswordEncoder());
encoders.put("SHA-1", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-1"));
encoders.put("SHA-256", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-256"));
encoders.put("sha256", new org.springframework.security.crypto.password.StandardPasswordEncoder());
encoders.put("argon2", new Argon2PasswordEncoder());
return new DelegatingPasswordEncoder(encodingId, encoders);
}
}