首页 > 编程语言 >[SpringSecurity5.6.2源码分析十]:HeaderWriterFilter

[SpringSecurity5.6.2源码分析十]:HeaderWriterFilter

时间:2023-09-16 15:00:59浏览次数:81  
标签:SpringSecurity5.6 request writers private final 源码 HeaderWriterFilter new respon

前言

  • • 为了安全考虑,添加启用浏览器保护的某些头是很有用的,比如X-Frame-Options, X-XSS-Protection和X-Content-Type-Options
  • • 而HeaderWriterFilter就支持往响应头写入各种响应头

1、HeadersConfigurer

  • • HeadersConfigurer是HeaderWriterFilter对应的配置类, 是在获取HttpSecurity的时候默认开启的,也可以通过HttpSecurity.headers()手动开启

1.1 主要方法

  • • 这个配置类主要就是为了注册HeaderWriter。分为两种配置方式,一种是用户自定义,一种是官方提供的
  • • HeaderWriter:负责写入响应头的类
  • • 第一种:
public HeadersConfigurer<H> addHeaderWriter(HeaderWriter headerWriter) {
   Assert.notNull(headerWriter, "headerWriter cannot be null");
   this.headerWriters.add(headerWriter);
   return this;
}
  • • 第二种:
/**
 * 下面全是头部写入器的配置类
 * 配置类是全部都new出来的,但是里面的头部写入器可能并没有开启
 */
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 {
   //将response包装为HeaderWriterResponse是为了在执行过程中就可以进行头部写入
   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;
   }

   /**
    * 此方法可以直接调用
    * 比如说Controller中执行response.(include,sendError, redirect, flushBuffer)的时候,此方法就会执行
    */
   @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()方法中被调用

[SpringSecurity5.6.2源码分析十]:HeaderWriterFilter_SrpingSecurity

image.png

  • • 我们再看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;
   }
});


标签:SpringSecurity5.6,request,writers,private,final,源码,HeaderWriterFilter,new,respon
From: https://blog.51cto.com/u_14008019/7493896

相关文章

  • springboot vue uniapp 小说电子书阅读小程序APP源码
    开发环境及工具:大等于jdk1.8,大于mysql5.5,idea(eclipse),nodejs,vscode(webstorm),HBuilderX技术说明:springbootmybatisvueelementuiuniapp代码注释齐全,没有多余代码,适合学习(毕设),二次开发,包含论文技术相关文档。功能介绍:用户端:登录注册首页显示搜索小说,轮播图,最新发布小说(可带推荐算......
  • 【DSP视频教程】DSP视频教程第12期:TI开源分享IQmath DSP源码,适用于所有Cortex-M内核,本
     今年TI推出MSPM0系列产品配套的SDK软件包里面将此库开源了,之前的时候也移植过IQmatb,不过只有库版本,这次竟然开源了,确实是不可多得的好资源。这个是定点库,非常适合用于M0,  M0+,  M3和不带硬件FPU的M4内核上,当然,用在M4F,M7,M33等器件上也是没问题的。本次视频配套的例子将ARMDS......
  • 阅读源码主题学习(I)
    一个程序员的技术水平的高低,是看他做过多少系统,更重要是看他踩过多少坑。阅读源码有哪些坑?源码阅读最难的不是代码本身,也不是理解其设计理念,而是坚持!职场小人开始说话了:1.工作中用的技术不需要阅读源码,在开发过程中熟练运用就行;2.看源码太费时间,而且容易忘记,实际使用中遇到问......
  • 二、 Axios入门—Axios源码分析
    一、axios与Axios的关系从语法上来说:axios不是Axios的实例从功能上来说:axios是Axios的实例axios是Axios.prototype.request函数bind()返回的函数axios作为对象有Axios原型对象上的所有方法,有Axios对象上所有属性二、instance与axios的区别相同:(1)都是一......
  • 基于Javaweb的物业管理系统的设计与实现-计算机毕业设计源码+LW文档
    摘 要随着目前信息化手段的进步,使用技术手段可以有效的对小区物业进行管理。在社区,人员多,各种维修、报修信息大,如果单靠人工进行管理,很难进行有效的统计。为此提出开发物业管理系统,来管理小区的业主信息、通知公告、报修管理、房产管理等。本物业管理系统可以降低社区工作者的劳......
  • 基于Javaweb汽车销售管理系统设计与实现-计算机毕业设计源码+LW文档
    摘 要随着因特网技术的迅速发展,当前人们的生活模式发生了巨大的变化。特别是在经济发展的影响下,汽车销售逐渐进入了人们的生活,并通过汽车销售系统进行汽车管理,方便用户在线销售、交流操作。当前城市生活节奏快,工作路程远,为了减少不必要的路途时间,许多用户选择使用自驾快速到达目......
  • 《Python从入门到实战》-源码篇-pyspider
    pyspider是什么?PySpider是一个开源的网络爬虫框架,使用Python语言编写。高效、易用、可扩展等特点,可以帮助用户快速地开发出高效的网络爬虫程序。PySpider支持多线程、分布式、异步IO等技术,可以处理大规模的数据爬取任务。同时,PySpider还提供了Web界面,方便用户进行任务管理和监控......
  • Vue源码学习(五):<templete>渲染第四步,生成虚拟dom并将其转换为真实dom
    好家伙, 前情提要:在上一篇我们已经成功将ast语法树转换为渲染函数 现在我们继续 1.项目目录代码已开源https://github.com/Fattiger4399/analytic-vue.git手动调试一遍,胜过我解释给你听一万遍新增文件:vnode/index.js  vnode/patch.js  lifecycle.js 2.虚......
  • mac版本Spring5.0源码环境搭建
    下载spring5.0版本代码链接是:https://github.com/spring-projects/spring-framework.git装gradle,使用的版本是8.3版本链接是:https://gradle.org/next-steps/?version=8.3&format=bin有错误提示:/Users/wangyu/work/code/spring-framework/buildSrc/src/main/java/org/springfra......
  • OpenWrt源码编译新增项
    OpenWrt源码编译新增项基于源码编译的openwrt,因为默认不是release版本,因此会砍掉一些东西。为了方便使用,自己经常会新增某些package,这里记录一些常用的package。luci.LuCIinterfacewithUhttpdasWebserver(default)luci-theme-argon.ArgonThemeluci-app-argon-confi......