Spring Security内置过滤器的维护方法

 更新时间:2022年02月22日 15:30:49   作者:码农小胖哥  
这篇文章主要介绍了Spring Security的内置过滤器是如何维护的,本文给我们分析一下HttpSecurity维护过滤器的几个方法,需要的朋友可以参考下

Spring Security中的内置过滤器顺序是怎么维护的?我想很多开发者都对这个问题感兴趣。本篇我和大家一起探讨下这个问题。

HttpSecurity包含了一个成员变量FilterOrderRegistration,这个类是一个内置过滤器注册表。至于这些过滤器的作用,不是本文介绍的重点,有兴趣可以去看看FilterOrderRegistration的源码。

内置过滤器的顺序

FilterOrderRegistration维护了一个变量filterToOrder,它记录了类之间的顺序和上下之间的间隔步长。我们复制了一个FilterOrderRegistration来直观感受一下过滤器的顺序:

CopyFilterOrderRegistration filterOrderRegistration = new CopyFilterOrderRegistration();
        // 获取内置过滤器  此方法并未提供
        Map<String, Integer> filterToOrder = filterOrderRegistration.getFilterToOrder();
        TreeMap<Integer, String> orderToFilter = new TreeMap<>();
        filterToOrder.forEach((name, order) -> orderToFilter.put(order,name));
        orderToFilter.forEach((order,name) -> System.out.println(" 顺序:" + order+" 类名:" + name ));

打印结果:

我们可以看得出内置过滤器之间的位置是相对固定的,除了第一个跟第二个步长为200外,其它步长为100。

内置过滤器并非一定会生效,仅仅是预置了它们的排位,需要通过HttpSecurity的addFilterXXXX系列方法显式添加才行。

注册过滤器的逻辑

FilterOrderRegistration提供了一个put方法:

 void put(Class<? extends Filter> filter, int position) {
  String className = filter.getName();
        // 如果这个类已经注册就忽略
  if (this.filterToOrder.containsKey(className)) {
   return;
  }
        // 如果没有注册就注册顺序。
  this.filterToOrder.put(className, position);
 }

从这个方法我们可以得到几个结论:

  • 内置的34个过滤器是有固定序号的,不可被改变。
  • 新加入的过滤器的类全限定名是不能和内置过滤器重复的。
  • 新加入的过滤器的顺序是可以和内置过滤器的顺序重复的。

获取已注册过滤器的顺序值

FilterOrderRegistration还提供了一个getOrder方法:

  Integer getOrder(Class<?> clazz) {
        // 如果类Class 或者 父类Class 名为空就返回null
        while (clazz != null) {
            Integer result = this.filterToOrder.get(clazz.getName());
            // 如果获取到顺序值就返回
            if (result != null) {
                return result;
            }
            // 否则尝试去获取父类的顺序值
            clazz = clazz.getSuperclass();
        }
        return null;
    }

HttpSecurity维护过滤器的方法

接下来我们分析一下HttpSecurity维护过滤器的几个方法。

addFilterAtOffsetOf

addFilterAtOffsetOf是一个HttpSecurity的内置私有方法。Filter是想要注册到DefaultSecurityFilterChain中的过滤器,offset是向右的偏移值,registeredFilter是已经注册到FilterOrderRegistration的过滤器,而且registeredFilter没有注册的话会空指针。

 private HttpSecurity addFilterAtOffsetOf(Filter filter, int offset, Class<? extends Filter> registeredFilter) {
        // 首先会根据registeredFilter的顺序和偏移值来计算filter的
  int order = this.filterOrders.getOrder(registeredFilter) + offset;
        // filter添加到集合中待排序
  this.filters.add(new OrderedFilter(filter, order));
        // filter注册到 FilterOrderRegistration
  this.filterOrders.put(filter.getClass(), order);
  return this;
 }

务必记着registeredFilter一定是已注册入FilterOrderRegistration的Filter。

addFilter系列方法

这里以addFilterAfter为例。

 @Override
 public HttpSecurity addFilterAfter(Filter filter, Class<? extends Filter> afterFilter) {
  return addFilterAtOffsetOf(filter, 1, afterFilter);
 }

addFilterAfter是将filter的位置置于afterFilter后一位,假如afterFilter顺序值为400,则filter顺序值为401。addFilterBefore和addFilterAt逻辑和addFilterAfter仅仅是偏移值的区别,这里不再赘述。

addFilter的方法比较特殊:

 @Override
 public HttpSecurity addFilter(Filter filter) {
  Integer order = this.filterOrders.getOrder(filter.getClass());
  if (order == null) {
   throw new IllegalArgumentException("The Filter class " + filter.getClass().getName()
     + " does not have a registered order and cannot be added without a specified order. Consider using addFilterBefore or addFilterAfter instead.");
  }
  this.filters.add(new OrderedFilter(filter, order));
  return this;
 }

filter必须是已经注册到FilterOrderRegistration的Filter,这意味着它可能是内置的Filter,也可能是先前通过addFilterBefore、addFilterAt或者addFilterAfter注册的非内置Filter。

问题来了

之前看到一个问题,如果HttpSecurity注册两个重复序号的Filter会是怎么样的顺序呢?我们先来看下排序的机制:

// filters
private List<OrderedFilter> filters = new ArrayList<>(); 
//排序
this.filters.sort(OrderComparator.INSTANCE);

看了下OrderComparator源码,其实还是通过数字的自然排序,数字越小越靠前。如果数字相同,索引越小越靠前。也就是同样的序号,谁先add到filters谁就越靠前。

到此这篇关于Spring Security的内置过滤器是如何维护的的文章就介绍到这了,更多相关Spring Security内置过滤器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • spring 定时任务@Scheduled详解

    spring 定时任务@Scheduled详解

    这篇文章主要介绍了spring 定时任务@Scheduled的相关资料,文中通过示例代码介绍的很详细,相信对大家的理解和学习具有一定的参考借鉴价值,有需要的朋友们下面来一起看看吧。
    2017-01-01
  • spring cloud 使用Eureka 进行服务治理方法

    spring cloud 使用Eureka 进行服务治理方法

    这篇文章主要介绍了spring cloud 使用Eureka 进行服务治理方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-05-05
  • 解析本地方法映射Java层的数据类型

    解析本地方法映射Java层的数据类型

    这篇文章给大家介绍了本地方法映射Java层的数据类型,包括基础类型映射,引用类型映射等等,对java层数据类型映射相关知识,感兴趣的朋友跟随脚本之家小编一起看看吧
    2018-03-03
  • 详解spring注解配置启动过程

    详解spring注解配置启动过程

    这篇文章主要为大家详细介绍了详解spring注解配置启动过程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-10-10
  • 详解Java后端优雅验证参数合法性

    详解Java后端优雅验证参数合法性

    这篇文章主要介绍了详解Java后端优雅验证参数合法性,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-02-02
  • Java中BeanUtils.copyProperties基本用法与小坑

    Java中BeanUtils.copyProperties基本用法与小坑

    本文主要介绍了Java中BeanUtils.copyProperties基本用法与小坑,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-04-04
  • maven工程打包引入本地jar包的实现

    maven工程打包引入本地jar包的实现

    我们需要将jar包发布到一些指定的第三方Maven仓库,本文主要介绍了maven工程打包引入本地jar包的实现,具有一定的参考价值,感兴趣的可以了解一下
    2024-02-02
  • 如何将文件流转换成byte[]数组

    如何将文件流转换成byte[]数组

    这篇文章主要介绍了如何将文件流转换成byte[]数组,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • Java实现去除文档阴影的示例代码

    Java实现去除文档阴影的示例代码

    文稿扫描大家用的都比较频繁、想是各种证件、文件都可以通过扫描文稿功能保存到手机。相比直接拍照,在扫描文稿时,程序会对图像进行一些矫正。比如去除阴影、修正倾斜、旋转矫正等。进行这些处理后的图片要更加容易识别。今天就来讨论一下去除阴影的操作
    2022-12-12
  • SpringBoot之自定义Schema扩展方式

    SpringBoot之自定义Schema扩展方式

    这篇文章主要介绍了SpringBoot之自定义Schema扩展方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09

最新评论