User-Profile-Image
hankin
  • 5
  • Java
  • Kotlin
  • Spring
  • Web
  • SQL
  • MegaData
  • More
  • Experience
  • Enamiĝu al vi
  • 分类
    • Zuul
    • Zookeeper
    • XML
    • WebSocket
    • Web Notes
    • Web
    • Vue
    • Thymeleaf
    • SQL Server
    • SQL Notes
    • SQL
    • SpringSecurity
    • SpringMVC
    • SpringJPA
    • SpringCloud
    • SpringBoot
    • Spring Notes
    • Spring
    • Servlet
    • Ribbon
    • Redis
    • RabbitMQ
    • Python
    • PostgreSQL
    • OAuth2
    • NOSQL
    • Netty
    • MySQL
    • MyBatis
    • More
    • MinIO
    • MegaData
    • Maven
    • LoadBalancer
    • Kotlin Notes
    • Kotlin
    • Kafka
    • jQuery
    • JavaScript
    • Java Notes
    • Java
    • Hystrix
    • Git
    • Gateway
    • Freemarker
    • Feign
    • Eureka
    • ElasticSearch
    • Docker
    • Consul
    • Ajax
    • ActiveMQ
  • 页面
    • 归档
    • 摘要
    • 杂图
    • 问题随笔
  • 友链
    • Spring Cloud Alibaba
    • Spring Cloud Alibaba - 指南
    • Spring Cloud
    • Nacos
    • Docker
    • ElasticSearch
    • Kotlin中文版
    • Kotlin易百
    • KotlinWeb3
    • KotlinNhooo
    • 前端开源搜索
    • Ktorm ORM
    • Ktorm-KSP
    • Ebean ORM
    • Maven
    • 江南一点雨
    • 江南国际站
    • 设计模式
    • 熊猫大佬
    • java学习
    • kotlin函数查询
    • Istio 服务网格
    • istio
    • Ktor 异步 Web 框架
    • PostGis
    • kuangstudy
    • 源码地图
    • it教程吧
    • Arthas-JVM调优
    • Electron
    • bugstack虫洞栈
    • github大佬宝典
    • Sa-Token
    • 前端技术胖
    • bennyhuo-Kt大佬
    • Rickiyang博客
    • 李大辉大佬博客
    • KOIN
    • SQLDelight
    • Exposed-Kt-ORM
    • Javalin—Web 框架
    • http4k—HTTP包
    • 爱威尔大佬
    • 小土豆
    • 小胖哥安全框架
    • 负雪明烛刷题
    • Kotlin-FP-Arrow
    • Lua参考手册
    • 美团文章
    • Java 全栈知识体系
    • 尼恩架构师学习
    • 现代 JavaScript 教程
    • GO相关文档
    • Go学习导航
    • GoCN社区
    • GO极客兔兔-案例
    • 讯飞星火GPT
    • Hollis博客
    • PostgreSQL德哥
    • 优质博客推荐
    • 半兽人大佬
    • 系列教程
    • PostgreSQL文章
    • 云原生资料库
    • 并发博客大佬
Help?

Please contact us on our email for need any support

Support
    首页   ›   Spring   ›   SpringSecurity   ›   正文
SpringSecurity

SpringSecurity addFilter() 顺序问题

2020-07-13 18:11:29
2068  0 0
参考目录 隐藏
1) FilterComparator
2) 1. HttpSecurity#addFilterAt
3) 2.HttpSecurity#addFilter(Filter filter)
4) 总结:

阅读完需:约 5 分钟

我们假设我们使用addFilterAt(A, B.class)。 即将A拦截器添加到B拦截器的位置。那么addFilterAt 既然没有覆盖原先的拦截器,那么A不是在B拦截器前面就是在B拦截器后面,那么岂不是和addFilterBefore 或者 addFilterAfter 重复了?

FilterComparator

为了更好的理解后面说的内容,我们需要先了解一下 FilterComparator 这个类。顾名思义,这个类是一个过滤器比较器。可以看到如下

其比较的规则如下, getOrder是根据类名来获取到过滤器的序号。可以看到过滤器的排序是根据排序序号的大小来排序的,序号小的在前,大的在后。

1. HttpSecurity#addFilterAt

我们这里拿 addFilterAt 举例,addFilterBefore 和 addFilterAfter 类似

先看第一句

this.comparator.registerAt(filter.getClass(), atFilter);

这里的 方法是 在 FilterComparator#registerAt 中
这里可以看到,当我们使用addFilterAt 添加过滤器时,他添加的排序序号是和我们指定的拦截器相同的。

简单来说,就是我们添加的 自己的 拦截器和 UsernamePasswordAuthenticationFilter 的序号是相同的。

2.HttpSecurity#addFilter(Filter filter)

代码很简单,如下,将添加的过滤器加到 filters 集合中

通过断点我们还可以发现,我们手动添加的过滤器是先于大部分系统过滤器被加入到filters集合中的。

另外从 HttpSecurity#performBuild 方法中我们可以知道,filters 在添加完所有过滤器后,使用 FilterComparator 比较器进行了比较。

总结:

  1. FilterComparator 比较器中初始化了Spring Security 自带的Filter 的顺序,即在 创建时已经确定了默认Filter的顺序。并将所有过滤器保存在一个 filterToOrder Map中。key值是Filter的类名,value是过滤器的顺序号。
  2. 当我们调用 HttpSecurity#addFilterAt(A, B.class) 方法时(其中B一定是先于A添加,或者B本身就是默认的过滤器),他会将我们的添加的过滤器A在 FilterComparator ,并给给我们一个和B相同的序号(addFilterBefore(A, B.class) 给A的序号比B小1,addFilterAfter(A, B.class) 给A的序号比B大1)。同时,HttpSecurity#addFilter(Filter filter) 会将我们添加的过滤器添加在 filters List集合中, 而在List集合汇总我们手动添加的拦截器在除了 WebAsyncManagerIntegrationFilter 之外的所有系统默认的拦截器之前。
  3. 最后Spring Security 会调用HttpSecurity#performBuild 方法,在这里会使用 FilterComparator 比较器对 filters进行比较排序,序号小的在前,序号大的在后,序号相等则按照原先的filters中的顺序。
  4. 由于在 filters List集合中,我们自己添加的过滤器要在除了 WebAsyncManagerIntegrationFilter 之外的所有系统默认的拦截器之前。导致了当我们调用了 HttpSecurity#addFilterAt(A, B.class) 方法时,A拦截器要先于B拦截器执行。

举例(为了好理解,纯属假设):

  1. 假设Spring Security 里面默认拦截器 有A、B、C 三个(在强调一遍,假设有这三个),那么 FilterComparator 构造函数中就有这三个拦截器的顺序值,假设Map值为{“AcName” : 100, “BcName” : 200, “CcName” : 300}。其中AcName是A拦截器的类名,BC同理,100,200,300是他们的序号,用于确定顺序。
  2. 我们添加一个拦截器 F 要调用addFilterAt(F, B.class)。那么它首先会在 FilterComparator 中注册F (保存在排序Map中),排序序号和B相同,也为 200,这时候Map 就变成了{“AcName” : 100, “BcName” : 200, “CcName” : 300, “FcName” : 200}。(如果调用addFilterBefore F的序号就会减1,变成199; 如果调用addFilterAfter F的序号就会加1,变成201)
  3. 在 完成上述步骤后,HttpSecurity 中也会把 F拦截器添加到一个待排序的List集合L中,然后在添加其他系统默认过滤器(相当于这个List保存了所有的过滤器,但是其调用顺序未确定,还需要经过排序后才能确定)。最终List集合L就变成了{ A, F, B, C},注意这个是未经排序的过滤器集合,排序后才是真正的调用顺序。
  4. 在调用 HttpSecurity#performBuild 方法时,会将HttpSecurity 中的过滤器集合L进行排序,排序比较器就是FilterComparator ,排序规则就是谁的排序序号小谁在前,序号大的在后,序号相同的保持 L 中的顺序。然后,得出最后的过滤器顺序,也就是最终调用顺序。

如本文“对您有用”,欢迎随意打赏作者,让我们坚持创作!

0 打赏
Enamiĝu al vi
不要为明天忧虑.因为明天自有明天的忧虑.一天的难处一天当就够了。
543文章 68评论 294点赞 593907浏览

随机文章
Java—ThreadPoolExecutor/ThreadPoolTaskExecutor 线程池技术提高系统吞吐量
5年前
SpringBoot—整合SpringSecurity(安全框架)
5年前
SpringSecurity—基础知识点与流程介绍
5年前
Spring—注解驱动开发Spring Ioc容器中注册Bean的7种方式
5年前
Java—并发编程(七)JUC集合 – (4) ConcurrentHashMap
4年前
博客统计
  • 日志总数:543 篇
  • 评论数目:68 条
  • 建站日期:2020-03-06
  • 运行天数:1927 天
  • 标签总数:23 个
  • 最后更新:2024-12-20
Copyright © 2025 网站备案号: 浙ICP备20017730号 身体没有灵魂是死的,信心没有行为也是死的。
主页
页面
  • 归档
  • 摘要
  • 杂图
  • 问题随笔
博主
Enamiĝu al vi
Enamiĝu al vi 管理员
To be, or not to be
543 文章 68 评论 593907 浏览
测试
测试
看板娘
赞赏作者

请通过微信、支付宝 APP 扫一扫

感谢您对作者的支持!

 支付宝 微信支付