前言
总结创建HttpSecuirty的创建过程,及其构建SecurityFilterChain过程。有和前面重复的地方,不管了…
触发HttpSecurity的创建过程
前面谈到,WebSecurity构建FilterChainProxy的过程中使用到了WebSecurityConfigurerAdapter的一个子类(这个子类一般需要用户定义的),调用了其init()。正是在这里,触发了HttpSecurity的构建过程。
public void init(final WebSecurity web) throws Exception {
//触发了HttpSecurity的构建
final HttpSecurity http = getHttp();
web.addSecurityFilterChainBuilder(http).postBuildAction(new Runnable() {
public void run() {
FilterSecurityInterceptor securityInterceptor = http
.getSharedObject(FilterSecurityInterceptor.class);
web.securityInterceptor(securityInterceptor);
}
});
}
创建HttpSecurity
protected final HttpSecurity getHttp() throws Exception {
if (http != null) {
return http;
}
DefaultAuthenticationEventPublisher eventPublisher = objectPostProcessor
.postProcess(new DefaultAuthenticationEventPublisher());
/*
* localConfigureAuthenticationBldr=“本地的授权管理器构建器”,它是可以由用户配置的
*/
localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);
/**
* 此方法用于创建“授权管理器”,比较重要,下文单独介绍。
* 使用“本地的授权管理器构建器”构建授权管理器
*/
AuthenticationManager authenticationManager = authenticationManager();
/**
* authenticationBuilder=“默认的的授权管理器”,这个是框架提供的默认配置
* 将使用本地配置构建的授权管理器,作为默认的授权管理器的父管理器
*/
authenticationBuilder.parentAuthenticationManager(authenticationManager);
/**
* 参数一:后置处理器,前面说过很多次了
* 参数二:授权管理器的构建器
* 参数三:HttpSecurity是用于构建真正处理请求的SecurityFilterChian,它使用了很多配置
* 器,这个配置器在创建的过程中可以共享一个对象(比如:ApplicationContext)。
* localConfigureAuthenticationBldr.getSharedObjects()用于获取用户自定义
* 共享对象。
*/
http = new HttpSecurity(objectPostProcessor, authenticationBuilder,
localConfigureAuthenticationBldr.getSharedObjects());
/**
* 设置共享对象。userDetailsService()方法后文详讨论。
*/
http.setSharedObject(UserDetailsService.class, userDetailsService());
http.setSharedObject(ApplicationContext.class, context);
http.setSharedObject(ContentNegotiationStrategy.class, contentNegotiationStrategy);
http.setSharedObject(AuthenticationTrustResolver.class, trustResolver);
/**
* 默认配置。
* 1)、添加了n多SecurityFilterChian的构建器的配置器
* 2)、直接添加了n多过滤器
* 关于每个配置的作用,将单列一章讨论。
*/
if (!disableDefaults) {
http
.csrf().and()
.addFilter(new WebAsyncManagerIntegrationFilter())
.exceptionHandling().and()
.headers().and()
.sessionManagement().and()
.securityContext().and()
.requestCache().and()
.anonymous().and()
.servletApi().and()
.apply(new DefaultLoginPageConfigurer<HttpSecurity>()).and()
.logout();
}
/**
* 此方法被用户重写去修改默认配置。
* 比如禁用csrf()、比如添加验证码校验、比如自定义权限认证
*/
configure(http);
return http;
}
使用本地配置构建授权管理器
protected AuthenticationManager authenticationManager() throws Exception {
if (!authenticationManagerInitialized) {
/**
* 这个方法由用户重写
*/
configure(localConfigureAuthenticationBldr);
/**
* 如果用户对configure(AuthenticationManagerBuilder auth)方法进行了重写,
* 那么,disableLocalConfigureAuthenticationBldr将为false,即:将使用用户的
* 配置来构建“授权管理器”
*/
if (disableLocalConfigureAuthenticationBldr) {
authenticationManager = authenticationConfiguration
.getAuthenticationManager();
}
else {
authenticationManager = localConfigureAuthenticationBldr.build();
}
authenticationManagerInitialized = true;
}
return authenticationManager;
}
创建共享对象UserDetailsService
@EnableWebSecurity这个注解其实也被@EnableGlobalAuthentication注解修饰。它导入了一个关于认证的配置类:AuthenticationConfiguration。这个类中,向容器中创建了AuthenticationManagerBuilder。
@Bean
public AuthenticationManagerBuilder authenticationManagerBuilder(
ObjectPostProcessor<Object> objectPostProcessor) {
return new AuthenticationManagerBuilder(objectPostProcessor);
}
为什么这么麻烦的获取UserDetailsService?
protected UserDetailsService userDetailsService() {
AuthenticationManagerBuilder globalAuthBuilder = context
.getBean(AuthenticationManagerBuilder.class);
return new UserDetailsServiceDelegator(Arrays.asList(
localConfigureAuthenticationBldr, globalAuthBuilder));
}
其实是SpringSecurity提供了两种设置UserDetailsService的方式
第一种:
@EnableWebSecurity
@ComponentScan("fn.wd.security")
public class SpringSecurityConfiger extends WebSecurityConfigurerAdapter {
@Autowired
private CustomUserDetailService customUserDetailService;
@Autowired
private AuthenticationManagerBuilder authenticationManagerBuilder;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
authenticationManagerBuilder.userDetailsService(customUserDetailService)
.passwordEncoder(standardPasswordEncoder());
}
}
第二种:
@EnableWebSecurity
@ComponentScan("fn.wd.security")
public class SpringSecurityConfiger extends WebSecurityConfigurerAdapter {
@Autowired
private CustomUserDetailService customUserDetailService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserDetailService)
.passwordEncoder(standardPasswordEncoder());
}
}
触发HttpSecurity的构建过程
HttpSecurity的构建过程是由WebSecurity构建具体的SecurityFilterChain时触发的:
protected Filter performBuild() throws Exception {
int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
List<SecurityFilterChain> securityFilterChains = new ArrayList<SecurityFilterChain>(
chainSize);
for (RequestMatcher ignoredRequest : ignoredRequests) {
securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
}
for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
//securityFilterChainBuilder.build()触发构建过程
securityFilterChains.add(securityFilterChainBuilder.build());
}
FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
if (httpFirewall != null) {
filterChainProxy.setFirewall(httpFirewall);
}
filterChainProxy.afterPropertiesSet();
Filter result = filterChainProxy;
postBuildAction.run();
return result;
}
定义构建的模版
不要忘记HttpSecurity和WebSecurity一样,都是AbstractConfiguredSecurityBuilder的子类。AbstractConfiguredSecurityBuilder中定义了构建的模版:
@Override
protected final O doBuild() throws Exception {
synchronized (configurers) {
buildState = BuildState.INITIALIZING;
beforeInit();
init();//调用所有配置器的init()
buildState = BuildState.CONFIGURING;
beforeConfigure();
configure();//调用所有配置器的configurer()
buildState = BuildState.BUILDING;
O result = performBuild();//最后调用HttpSecurity中performBuild的实现
buildState = BuildState.BUILT;
return result;
}
}
构建SecurityFilterChain
由于这个构建器(HttpSecurity)里面的构建器配置器很多,所以init()、configurer()会比较复杂,后面详讨论吧,这里重点看下HttpSecurity的performBuild():
@Override
protected DefaultSecurityFilterChain performBuild() throws Exception {
//comparator其实就是FilterComparator的对象
Collections.sort(filters, comparator);
return new DefaultSecurityFilterChain(requestMatcher, filters);
}
可以看到的是,HttpSecurity只是将配置器配置的结果(filters)按照某种规则(FilterComparator)排序。
FilterComparator内部其实已经定义了框架提供的过滤器的顺序。当我们向过滤器链中插入一个过滤器(比如:插入校验验证码的过滤器)时,不仅是将此过滤器添加到HttpSecurity的配置中,还修改了这个比较器。比如HttpSecurity的addFilterBefore()方法:
public HttpSecurity addFilterBefore(Filter filter,
Class<? extends Filter> beforeFilter) {
//先修改比较器
comparator.registerBefore(filter.getClass(), beforeFilter);
//然后才添加到配置中
return addFilter(filter);
}