笔者在学习Spring Security,调试HeaderWriterFilter源码时,遇到了一个比较困惑的问题,HeaderWriterFilter在往请求头写入信息时,通过shouldWriteHeadersEagerly这个变量来控制,在调用过滤器之前写入还是调用doFilter()之后将信息写入到请求头当中,默认是过滤链执行后写入。笔者以为可以在ResourceServerConfig#configure()方法中,调用HttpSecurity.headers()进行配置,但并没有找到配置方法。笔者把Spring Security源码给下到了本地,在官方的测试用例中找到了答案,而且与这篇文章要介绍的 ObjectPostProcessor有关,代码如下:
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
if (this.shouldWriteHeadersEagerly) {
doHeadersBefore(request, response, filterChain);
} else {
doHeadersAfter(request, response, filterChain);
}
}
@EnableWebSecurity
public static class HeadersAtTheBeginningOfRequestConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
//@ formatter:off
http
.headers()
.addObjectPostProcessor(new ObjectPostProcessor<HeaderWriterFilter>() {
@Override
public HeaderWriterFilter postProcess(HeaderWriterFilter filter) {
filter.setShouldWriteHeadersEagerly(true);
return filter;
}
});
//@ formatter:on
}
}
我们在学习Spring Security Filter源码的时候,会发现,相关的Filter都是以new的形式创建的,作为Java服务端开发,我们知道,new出来的对象是不受Spring Bean生命周期管控的。为了使这些Filter实例能够被Spring Bean容器管理,Spring Security定义了一个接口ObjectPostProcessor,AutowireBeanFactoryObjectPostProcessor实现了这个接口,通过postProcess方法手把Bean注入到spring容器进行管理。
AutowireBeanFactoryObjectPostProcessor注册到Spring Bean容器,是通过@EnableWebSecurity注解一步步@Import实现的,代码如下:
// @EnableWebSecurity 注解代码片段,可以看到该注解隐含使用了@EnableGlobalMethodSecurity
@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;
}
// @EnableGlobalAuthentication 注解代码片段,可以看到它导入了类 AuthenticationConfiguration
@Import(AuthenticationConfiguration.class)
@Configuration
public @interface EnableGlobalAuthentication {
}
@Configuration
@Import(ObjectPostProcessorConfiguration.class) // 导入了类 ObjectPostProcessorConfiguration
public class AuthenticationConfiguration {
// 省略无关代码实现
}
@Configuration
public class ObjectPostProcessorConfiguration {
// 这里的参数beanFactory会被自动注入成当前Spring bean容器
@Bean
public ObjectPostProcessor<Object> objectPostProcessor(
AutowireCapableBeanFactory beanFactory) {
return new AutowireBeanFactoryObjectPostProcessor(beanFactory);
}
}
AutowireBeanFactoryObjectPostProcessor的代码分析笔者对代码的关键位置做了比较详细的注释,如下:
package org.springframework.security.config.annotation.configuration;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.Aware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.util.Assert;
final class AutowireBeanFactoryObjectPostProcessor
implements ObjectPostProcessor<Object>, DisposableBean, SmartInitializingSingleton {
private final Log logger = LogFactory.getLog(getClass());
private final AutowireCapableBeanFactory autowireBeanFactory;
private final List<DisposableBean> disposableBeans = new ArrayList<>();
private final List<SmartInitializingSingleton> smartSingletons = new ArrayList<>();
// 使用指定的 autowireBeanFactory 构造对象
// autowireBeanFactory 通常是 Spring bean 容器
public AutowireBeanFactoryObjectPostProcessor(
AutowireCapableBeanFactory autowireBeanFactory) {
Assert.notNull(autowireBeanFactory, "autowireBeanFactory cannot be null");
this.autowireBeanFactory = autowireBeanFactory;
}
// 对某个刚刚创建的对象 object 执行这里所谓的 post-process 流程 :
// 1. 使用指定的 autowireBeanFactory 对该对象 object 执行初始化过程;
// 2. 使用指定的 autowireBeanFactory 对该对象 object 执行依赖注入过程;
// 3. 如果该对象 object 是一个 DisposableBean , 则将它记录下来,在当前对象的destroy()
// 被调用时,它们的 destroy() 方法也都会被调用;
// 4. 如果该对象 object 是一个 SmartInitializingSingleton , 则将它记录下来,
// 在当前对象的 afterSingletonsInstantiated () 被调用时,它们的 afterSingletonsInstantiated()
// 方法也都会被调用;
@SuppressWarnings("unchecked")
public <T> T postProcess(T object) {
if (object == null) {
return null;
}
T result = null;
try {
// 使用容器autowireBeanFactory标准初始化方法initializeBean()初始化对象 object
result = (T) this.autowireBeanFactory.initializeBean(object,
object.toString());
}
catch (RuntimeException e) {
Class<?> type = object.getClass();
throw new RuntimeException(
"Could not postProcess " + object + " of type " + type, e);
}
// 使用容器autowireBeanFactory标准依赖注入方法autowireBean()处理 object对象的依赖注入
this.autowireBeanFactory.autowireBean(object);
if (result instanceof DisposableBean) {
// 记录一个 DisposableBean 对象
this.disposableBeans.add((DisposableBean) result);
}
if (result instanceof SmartInitializingSingleton) {
// 记录一个 SmartInitializingSingleton 对象
this.smartSingletons.add((SmartInitializingSingleton) result);
}
return result;
}
// SmartInitializingSingleton 接口定义的生命周期方法,在被调用时也回调用被记录的实现了
// SmartInitializingSingleton 接口的那些对象的方法 afterSingletonsInstantiated()
@Override
public void afterSingletonsInstantiated() {
for (SmartInitializingSingleton singleton : smartSingletons) {
singleton.afterSingletonsInstantiated();
}
}
// DisposableBean 接口定义的生命周期方法,在被调用时也回调用被记录的实现了
// DisposableBean 接口的那些对象的方法 destroy()
public void destroy() throws Exception {
for (DisposableBean disposable : this.disposableBeans) {
try {
disposable.destroy();
}
catch (Exception error) {
this.logger.error(error);
}
}
}
}
ObjectPostProcessor在Spring Security中广泛应用,我们这里就以HeaderWriterFilter为例, 像文章开始说的那样,笔者要修改shouldWriteHeadersEagerly的值,可以进行如下配置:
@Override
public void configure(HttpSecurity http) throws Exception {
http.headers()
.addObjectPostProcessor(new ObjectPostProcessor<HeaderWriterFilter>() {
@Override
public HeaderWriterFilter postProcess(HeaderWriterFilter filter) {
filter.setShouldWriteHeadersEagerly(true);
return filter;
}
});
}
在HeaderConfigurer这个类中,HeaderWriterFilter确实是new出来的,接着调用了postProcess()方法,进行后置处理。objectPostProcessor是一个复合的对象后置处理器,内部维护一个ObjectPostProcessor List, 调用postProcess()时,遍历ObjectPostProcessor List逐一处理传入的对象。这个List是在默认情况下,只包含一个ObjectPostProcessor,实现就是AutowireBeanFactoryObjectPostProcessor,但是我们自己配置了http.headers().addObjectPostProcessor(…),因此还有一个匿名ObjectPostProcessor,前者是将对象注入到Spring Bean容器,或者是显式调用容器中bean的方法改变对象的属性。CompositeObjectPostProcessor关键代码如下:
private CompositeObjectPostProcessor objectPostProcessor = new CompositeObjectPostProcessor();
private HeaderWriterFilter createHeaderWriterFilter() {
List<HeaderWriter> writers = getHeaderWriters();
if (writers.isEmpty()) {
throw new IllegalStateException(
"Headers security is enabled, but no headers will be added. Either add headers or disable headers security");
}
HeaderWriterFilter headersFilter = new HeaderWriterFilter(writers);
headersFilter = postProcess(headersFilter);
return headersFilter;
}
protected <T> T postProcess(T object) {
return (T) this.objectPostProcessor.postProcess(object);
}
private List<ObjectPostProcessor<?>> postProcessors = new ArrayList<>();
@SuppressWarnings({ "rawtypes", "unchecked" })
public Object postProcess(Object object) {
for (ObjectPostProcessor opp : postProcessors) {
Class<?> oppClass = opp.getClass();
Class<?> oppType = GenericTypeResolver.resolveTypeArgument(oppClass,
ObjectPostProcessor.class);
if (oppType == null || oppType.isAssignableFrom(object.getClass())) {
object = opp.postProcess(object);
}
}
return object;
}
项目启动后看,我们发起一个请求,发现shouldWriteHeadersEagerly已经为true了,截图如下: