SpringSecurity------HttpSecurityConfiguration配置类
一、HttpSecurityConfiguration是怎样被加载的
通过@EnableWebSecurity注解上的@Import()注解引入的
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import({ WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class,
HttpSecurityConfiguration.class })
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity {
/**
* Controls debugging support for Spring Security. Default is false.
* @return if true, enables debug support with Spring Security
*/
boolean debug() default false;
}
二、HttpSecurityConfiguration主要做了什么
首先,他会通过@Autowired去获取容器中的一个AuthenticationManager实例,如果没能获取到则使用依赖注入的AuthenticationConfiguration实例创建一个AuthenticationManager实例,这个实例其实就是ProviderManager。以上介绍就是当前配置类中的authenticationManager()方法的实现方式。
然后,他会创建一个AuthenticationManagerBuilder(使用的是DefaultPasswordEncoderAuthenticationManagerBuilder),使用的密码编码器是LazyPasswordEncoder,同时将这个建造器的Parent-AuthenticationManager设置成当前配置类创建的AuthenticationManager(这里其实就是ProviderManager的一个实例)。
接着,使用DefaultPasswordEncoderAuthenticationManagerBuilder这个建造器构建一个HttpSecurity实例,并为HttpSecurity设置了一些默认配置。这个单例的HttpSecurity会被注入到容器中,用户就可以使用他进行自定义的鉴权配置了。
三、HttpSecurityConfiguration的源码分析
1、属性字段
//类名前缀
private static final String BEAN_NAME_PREFIX =
"org.springframework.security.config.annotation.web.configuration.HttpSecurityConfiguration.";
//在容器中的HttpSecurit实例名称
private static final String HTTPSECURITY_BEAN_NAME = BEAN_NAME_PREFIX + "httpSecurity";
//对象后处理器
private ObjectPostProcessor<Object> objectPostProcessor;
//鉴权管理器
private AuthenticationManager authenticationManager;
//鉴权管理器的配置,如果没有从容器中获取到AuthenticationManager,会使用该配置创建一个AuthenticationManager
private AuthenticationConfiguration authenticationConfiguration;
//容器
private ApplicationContext context;
2、核心方法
@Bean(HTTPSECURITY_BEAN_NAME)
@Scope("prototype")
HttpSecurity httpSecurity() throws Exception {
//密码编码器
WebSecurityConfigurerAdapter.LazyPasswordEncoder passwordEncoder =
new WebSecurityConfigurerAdapter.LazyPasswordEncoder(
this.context);
//AuthenticationManager建造器
AuthenticationManagerBuilder authenticationBuilder =
new WebSecurityConfigurerAdapter.DefaultPasswordEncoderAuthenticationManagerBuilder(
this.objectPostProcessor, passwordEncoder);
//获取AuthenticationManager(ProviderManager),设置为父AuthenticationManager,用于管理所有的AuthenticationProvider
authenticationBuilder.parentAuthenticationManager(authenticationManager());
//创建一个HttpSecurity,相当于xml文件配置中的http名称空间
HttpSecurity http = new HttpSecurity(this.objectPostProcessor, authenticationBuilder, createSharedObjects());
//这里有一些默认的配置
http
.csrf(withDefaults())
.addFilter(new WebAsyncManagerIntegrationFilter())
.exceptionHandling(withDefaults())
.headers(withDefaults())
.sessionManagement(withDefaults())
.securityContext(withDefaults())
.requestCache(withDefaults())
.anonymous(withDefaults())
.servletApi(withDefaults())
.logout(withDefaults())
.apply(new DefaultLoginPageConfigurer<>());
return http;
}
获取AuthenticationManager(ProviderManager),如果已经初始化就直接返回,如果没有就直接使用authenticationConfiguration配置类创建一个
private AuthenticationManager authenticationManager() throws Exception {
return (this.authenticationManager != null) ? this.authenticationManager
: this.authenticationConfiguration.getAuthenticationManager();
}
将ApplicationContext包装起来供HttpSecurity使用
private Map<Class<?>, Object> createSharedObjects() {
Map<Class<?>, Object> sharedObjects = new HashMap<>();
sharedObjects.put(ApplicationContext.class, this.context);
return sharedObjects;
}
3、使用@Autowired注入了一些Bean
提供Spring的生命周期支持,主要是用于创建对象。这里注入的是AutowireBeanFactoryObjectPostProcessor类的一个实例
@Autowired
void setObjectPostProcessor(ObjectPostProcessor<Object> objectPostProcessor) {
this.objectPostProcessor = objectPostProcessor;
}
鉴权对象,这里注入的是ProviderManager的一个实例(有可能在该类初始化的时候容器中还不存在ProviderManager)
@Autowired(required = false)
void setAuthenticationManager(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
用于构建ProviderManager的一个配置类
@Autowired
void setAuthenticationConfiguration(AuthenticationConfiguration authenticationConfiguration) {
this.authenticationConfiguration = authenticationConfiguration;
}
Spring容器
@Autowired
void setApplicationContext(ApplicationContext context) {
this.context = context;
}