前言
为了安全考虑,添加启用浏览器保护的某些头是很有用的,比如X-Frame-Options, X-XSS-Protection和X-Content-Type-Options 而HeaderWriterFilter就支持往响应头写入各种响应头
1、HeadersConfigurer
HeadersConfigurer是HeaderWriterFilter对应的配置类, 是在获取HttpSecurity的时候默认开启的,也可以通过HttpSecurity.headers()手动开启
1.1 主要方法
这个配置类主要就是为了注册HeaderWriter。分为两种配置方式,一种是用户自定义,一种是官方提供的
第一种:
public HeadersConfigurer < H > addHeaderWriter ( HeaderWriter headerWriter) {
Assert . notNull ( headerWriter, "headerWriter cannot be null" ) ;
this . headerWriters. add ( headerWriter) ;
return this ;
}
private final ContentTypeOptionsConfig contentTypeOptions = new ContentTypeOptionsConfig ( ) ;
private final XXssConfig xssProtection = new XXssConfig ( ) ;
private final CacheControlConfig cacheControl = new CacheControlConfig ( ) ;
private final HstsConfig hsts = new HstsConfig ( ) ;
private final FrameOptionsConfig frameOptions = new FrameOptionsConfig ( ) ;
private final HpkpConfig hpkp = new HpkpConfig ( ) ;
private final ContentSecurityPolicyConfig contentSecurityPolicy = new ContentSecurityPolicyConfig ( ) ;
private final ReferrerPolicyConfig referrerPolicy = new ReferrerPolicyConfig ( ) ;
private final FeaturePolicyConfig featurePolicy = new FeaturePolicyConfig ( ) ;
private final PermissionsPolicyConfig permissionsPolicy = new PermissionsPolicyConfig ( ) ;
1.2 构建流程
HeadersConfigurer只重写了configure(…)方法:内部就是创建过滤器
@Override
public void configure ( H http) {
HeaderWriterFilter headersFilter = createHeaderWriterFilter ( ) ;
http. addFilter ( headersFilter) ;
}
HeaderWriterFilter中的头部写入器 = 用户自定义 + 默认配置类中开启的
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;
}
private List < HeaderWriter > getHeaderWriters ( ) {
List < HeaderWriter > writers = new ArrayList < > ( ) ;
addIfNotNull ( writers, this . contentTypeOptions. writer) ;
addIfNotNull ( writers, this . xssProtection. writer) ;
addIfNotNull ( writers, this . cacheControl. writer) ;
addIfNotNull ( writers, this . hsts. writer) ;
addIfNotNull ( writers, this . frameOptions. writer) ;
addIfNotNull ( writers, this . hpkp. writer) ;
addIfNotNull ( writers, this . contentSecurityPolicy. writer) ;
addIfNotNull ( writers, this . referrerPolicy. writer) ;
addIfNotNull ( writers, this . featurePolicy. writer) ;
addIfNotNull ( writers, this . permissionsPolicy. writer) ;
writers. addAll ( this . headerWriters) ;
return writers;
}
2、HeaderWriterFilter
2.1 doFilterInternal(…)
我们直接看doFilterInternal(…)方法:可以看出过滤器支持在请求的前后写入响应头
@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) ;
}
}
doHeadersBefore(…):此方法就是调用HeaderWriter写入响应头,然后执行后续的过滤器
private void doHeadersBefore ( HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws IOException , ServletException {
writeHeaders ( request, response) ;
filterChain. doFilter ( request, response) ;
}
doHeadersAfter(…):此方法稍微复杂点,这里包装了request和response
private void doHeadersAfter ( HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws IOException , ServletException {
HeaderWriterResponse headerWriterResponse = new HeaderWriterResponse ( request, response) ;
HeaderWriterRequest headerWriterRequest = new HeaderWriterRequest ( request, headerWriterResponse) ;
try {
filterChain. doFilter ( headerWriterRequest, headerWriterResponse) ;
}
finally {
headerWriterResponse. writeHeaders ( ) ;
}
}
我们主要看下HeaderWriterResponse的源码,主要就是重写了onResponseCommitted()方法
class HeaderWriterResponse extends OnCommittedResponseWrapper {
private final HttpServletRequest request;
HeaderWriterResponse ( HttpServletRequest request, HttpServletResponse response) {
super ( response) ;
this . request = request;
}
@Override
protected void onResponseCommitted ( ) {
writeHeaders ( ) ;
this . disableOnResponseCommitted ( ) ;
}
protected void writeHeaders ( ) {
if ( isDisableOnResponseCommitted ( ) ) {
return ;
}
HeaderWriterFilter . this . writeHeaders ( this . request, getHttpResponse ( ) ) ;
}
private HttpServletResponse getHttpResponse ( ) {
return ( HttpServletResponse ) getResponse ( ) ;
}
}
2.2 shouldWriteHeadersEagerly
前面我们提到了HeaderWriter的执行顺序是通过shouldWriteHeadersEagerly这个标志位来决定,但是这个标志位不可以在HeadersConfigurer中直接配置 但是我们前面提到了所有的过滤器都有一个基于ObjectPostProcessor的回调方法,这个回调方法在HeadersConfigurer的createHeaderWriterFilter()方法中被调用
我们再看postProcess(…)方法的源码:
分析可知道这是遍历所有的ObjectPostProcessor,然后看有哪些ObjectPostProcessor的泛型和传入的object一样,一样就执行回调方法
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的值
http. headers ( ) . addObjectPostProcessor ( new ObjectPostProcessor < HeaderWriterFilter > ( ) {
@Override
public < O extends HeaderWriterFilter > O postProcess ( O object) {
HeaderWriterFilter filter = object;
filter. setShouldWriteHeadersEagerly ( true ) ;
return object;
}
} ) ;