Spring Security的内置过滤器是如何维护的

举报
码农小胖哥 发表于 2022/03/31 23:11:59 2022/03/31
【摘要】 2022年的开工福利已经发布,点击下面按钮获取最新PDF。 Spring Security中的内置过滤器顺序是怎么维护的?我想很多开发者都对这个问题感兴趣。本篇我和大家一起探讨下这个问题。 HttpSecurity包含了一个成员变量FilterOrderRegistration,这个类是一个内置过滤器注册表。至于这些过...

cb45de3bfdf7db7a2852da8ccc05c2de.gif

2022年的开工福利已经发布,点击下面按钮获取最新PDF。

c4ba20262561715f52f7773f9704f36d.png

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

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

内置过滤器的顺序

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


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

打印结果:

271b8b1a5524eac36ddad295be3cb781.png

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

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

注册过滤器的逻辑

FilterOrderRegistration提供了一个put方法:


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

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

  • 内置的34个过滤器是有固定序号的,不可被改变。

  • 新加入的过滤器的类全限定名是不能和内置过滤器重复的。

  • 新加入的过滤器的顺序是可以和内置过滤器的顺序重复的。

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

FilterOrderRegistration还提供了一个getOrder方法:


   
  1. Integer getOrder(Class<?> clazz) {
  2.         // 如果类Class 或者 父类Class 名为空就返回null
  3.         while (clazz != null) {
  4.             Integer result = this.filterToOrder.get(clazz.getName());
  5.             // 如果获取到顺序值就返回
  6.             if (result != null) {
  7.                 return result;
  8.             }
  9.             // 否则尝试去获取父类的顺序值
  10.             clazz = clazz.getSuperclass();
  11.         }
  12.         return null;
  13.     }

HttpSecurity维护过滤器的方法

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

addFilterAtOffsetOf

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


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

务必记着registeredFilter一定是已注册入FilterOrderRegistrationFilter

addFilter系列方法

这里以addFilterAfter为例。


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

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

addFilter的方法比较特殊:


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

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

问题来了

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


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

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

附DEMO| 绝活!Spring Security过滤器就该这么配置

2022-02-16

51d3e05086b1528ca752d67f93988009.png

OAuth2授权服务器Keycloak宣布不再适配Spring Boot和Spring Security

2022-02-15

8e8c65479d39008e6efa8c83829b9631.png

Spring Security过滤器链如何匹配到特定的请求

2022-02-14

a1ec018bb8afd338103348767e263d7f.png

通过以下公众号回复 2022开工福利 就可以获得原创PDF

4b3444afe2e3b7545e4089f9f27cd58f.gif

文章来源: felord.blog.csdn.net,作者:码农小胖哥,版权归原作者所有,如需转载,请联系作者。

原文链接:felord.blog.csdn.net/article/details/123059346

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。