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

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

注册过滤器的逻辑

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 名为空就返回nullwhile (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注册到 FilterOrderRegistrationthis.filterOrders.put(filter.getClass(), order);return this;}

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

addFilter系列方法

这里以addFilterAfter为例。

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

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

addFilter的方法比较特殊:

@Overridepublic 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必须是已经注册到FilterOrderRegistrationFilter,这意味着它可能是内置的Filter,也可能是先前通过addFilterBeforeaddFilterAt或者addFilterAfter注册的非内置Filter

问题来了

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

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

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

------

我们创建了一个高质量的技术交流群,与优秀的人在一起,自己也会优秀起来,赶紧点击加群,享受一起成长的快乐。另外,如果你最近想跳槽的话,年前我花了2周时间收集了一波大厂面经,节后准备跳槽的可以点击这里领取!

推荐阅读

  • 在公司wiki发布“女优一览表”遭开除

  • GitHub上发现个菜谱仓库

  • 领了红包不点赞,就是傻逼?

··································

你好,我是程序猿DD,10年开发老司机、阿里云MVP、腾讯云TVP、出过书、创过业、国企4年互联网6年。10年前毕业加入宇宙行,工资不高、也不算太忙,业余坚持研究技术和做自己想做的东西。4年后离开国企,加入永辉互联网板块的创业团队,从开发、到架构、到合伙人。一路过来,给我最深的感受就是一定要不断学习并关注前沿。只要你能坚持下来,多思考、少抱怨、勤动手,就很容易实现弯道超车!所以,不要问我现在干什么是否来得及。如果你看好一个事情,一定是坚持了才能看到希望,而不是看到希望才去坚持。相信我,只要坚持下来,你一定比现在更好!如果你还没什么方向,可以先关注我,这里会经常分享一些前沿资讯,帮你积累弯道超车的资本。

点击阅读原文,领取2022最新10000T学习资料

Spring Security的内置过滤器是如何维护的?相关推荐

  1. Spring Cloud Gateway内置过滤器实战——AddResponseHeader过滤器工厂

    一 代码位置 https://github.com/cakin24/spring-cloud-code/tree/master/ch17-3/ch17-3-4-gateway https://gith ...

  2. Spring Cloud Gateway内置的断言和过滤器作用

    文章目录 前言 一.内置断言 二.内置过滤器 1.GlobalFilter 2.GatewayFilter 三.配置参数解析模式 1.DEFAULT 2.GATHER_LIST 3.GATHER_LI ...

  3. gateway内置过滤器工厂

    Spring Cloud Gateway 内置的过滤器工厂 内置的过滤器工厂 这里简单将Spring Cloud Gateway内置的所有过滤器工厂整理成了一张表格.如下: 过滤器工厂 作用 参数 A ...

  4. Shiro的内置过滤器没有生效

    Shiro的内置过滤器没有生效 在学习shiro时,对某些访问路径设置过滤器,如filterMap.put("/user/add","authc");但是设置好 ...

  5. angularJS 组件及内置过滤器

    组件化<component> 组件化是将页面中一部分UI封装起来进行重复使用,UI中的数据可以是不同的,甚至组件中可以对UI进行适当的业务逻辑处理,如链接跳转.数据运算等等 组件语法结构如 ...

  6. apache shiro内置过滤器 标签 注解

    内置过滤器 anon(匿名)  org.apache.shiro.web.filter.authc.AnonymousFilter authc(身份验证)       org.apache.shiro ...

  7. Django中的内置过滤器

    Django的内置过滤器

  8. angularjs读书笔记:angularjs内置过滤器总结——摘自《Angularjs权威教程》

    过滤器用来格式化需要展示给用户的数据.AngularJS有很多实用的内置过滤器,同时也提 供了方便的途径可以自己创建过滤器. 在HTML中的模板绑定符号{{ }}内通过|符号来调用过滤器.例如,假设我 ...

  9. Spring Security内置过滤器详解

    相关文章: OAuth2的定义和运行流程 Spring Security OAuth实现Gitee快捷登录 Spring Security OAuth实现GitHub快捷登录 Spring Secur ...

最新文章

  1. SecureCRT连接CentOS阿里云,小键盘在VIM情况下,无法输入数字反而出现英文
  2. 深入理解Java的三种工厂模式
  3. 移动设备测试 6 free mobile device emulators for testing your site
  4. MyBatis3源码解析(4)参数解析
  5. Nginx 作为Http代理服务器配置
  6. 网络代理服务器工作原理
  7. My97DatePicker组件使用方法
  8. 可孚医疗的数字化突围
  9. 管理型工业以太网交换机什么
  10. 数据结构PTA 案例6-1.3 哥尼斯堡的“七桥问题”
  11. 批处理程序文件夹加密
  12. 苹果开发者中心如何上传构建版本
  13. mysql-mmm vip 切换问题_mysql-mmm复制延迟的想法
  14. 【定量分析、量化金融与统计学】R语言方差分析的outliers陷阱
  15. SpringCloud(3)CloudAlibaba Nacos Sentinel Seata
  16. 计算机键盘手指放置,键盘上手指放置的位置图
  17. (翻译)你想做用户体验经理吗?
  18. echarts 动态数据动画效果
  19. 读论文《Natural Language Processing (Almost) from Scratch》
  20. MATLAB--数值计算(矩阵)

热门文章

  1. pcDuino 软件更新
  2. linux socket无延迟发送数据
  3. 改善代码设计 —— 组织好你的数“.NET研究”据(Composing Data)
  4. 拼图游戏 复制粘贴一个叫lemene的人的,这个人是c++博客的用户,我不是,怕以后找不到这篇文章,所以复制粘贴了。文中最后给出了原文链接连接...
  5. 海蜘蛛如何手工升级到最新版
  6. 驳“AJAX 的七宗罪”
  7. 开发出高性能的网站系列文章
  8. python3 实现 php bin2hex 函数
  9. easyui 添加 自定义图标
  10. linux c 函数 link symlink unlink 链接相关功能