首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Spring Security过滤器的排序规则

Spring Security过滤器的排序规则

作者头像
码农小胖哥
发布于 2022-05-22 01:46:41
发布于 2022-05-22 01:46:41
1.5K00
代码可运行
举报
运行总次数:0
代码可运行

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

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

内置过滤器的顺序

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        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方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 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方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    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没有注册的话会空指针。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 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一定是已注册入FilterOrderRegistrationFilter

addFilter系列方法

这里以addFilterAfter为例。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 @Override
 public HttpSecurity addFilterAfter(Filter filter, Class<? extends Filter> afterFilter) {
  return addFilterAtOffsetOf(filter, 1, afterFilter);
 }

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

addFilter的方法比较特殊:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 @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必须是已经注册到FilterOrderRegistrationFilter,这意味着它可能是内置的Filter,也可能是先前通过addFilterBeforeaddFilterAt或者addFilterAfter注册的非内置Filter

问题来了

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// filters
private List<OrderedFilter> filters = new ArrayList<>(); 
//排序
this.filters.sort(OrderComparator.INSTANCE);

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

另外最近胖哥有很多成系列的内容输出:

  • OAuth2 系列教程,已经更新了40多篇。
  • 开源了一个登录组件扩展spring-security-login-extension,降低对接配置成本,欢迎学习、star
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-04-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码农小胖哥 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
Go语言实战笔记(二)| Go开发工具
在Go语言中,我们很多操作都是通过go命令进行的,比如我们要执行go文件的编译,就需要使用go build命令,除了build命令之外,还有很多常用的命令,这一次我们就统一进行介绍,对常用命令有一个了解,这样我们就可以更容易的开发我们的Go程序了。
飞雪无情
2018/08/28
7150
深度阅读之《Mastering Go》
写在前面:这本书前前后后花了挺长时间,去年 11 月份就开始读了,中间又断了,直到最近才捡起来看完。
梦醒人间
2021/04/23
7010
深度阅读之《Mastering Go》
Machine Learning With Go 第4章:回归
我们将探究的第一组机器学习技术通常被称为回归(regression),我们可以将回归理解为一个变量(例如销售额)的变化是如何影响到其他变量(如用户数)的。对于机器学习技术来说,这是一个很好的开端,它们是构成其他更加复杂技术的基础。
charlieroro
2022/06/02
1.6K0
Machine Learning With Go 第4章:回归
Go语言交叉编译工具gox
交叉编译是为了在不同平台编译出其他平台的程序,比如在Linux编译出Windows程序,在Windows能编译出Linux程序,32位系统下编译出64位程序,今天介绍的gox就是其中一款交叉编译工具。
平也
2020/04/03
1.8K0
使用 Act 本地运行 GitHub Actions
GitHub Actions 为仓库开发者提供了执行定制化 Job 的能力,开发者可以使用各种 Job 基于代码仓库运行测试、构建、发布等操作,实现 CI/CD 等工作流。
陆道峰
2024/07/02
1.5K0
使用 Act 本地运行 GitHub Actions
爬虫+反爬虫+js代码混淆
在日常开发工作业务场景中,你可能会遇到重复性的业务工作脚本功能维护。笔者分析了下,其在修改业务代码后,大致都会遇到如下问题:
李昂君
2023/03/16
4K0
爬虫+反爬虫+js代码混淆
Go 每日一库之 plot
本文介绍 Go 语言的一个非常强大、好用的绘图库——plot。plot内置了很多常用的组件,基本满足日常需求。同时,它也提供了定制化的接口,可以实现我们的个性化需求。plot主要用于将数据可视化,便于我们观察、比较。
用户7731323
2020/09/08
1.5K0
Golang开发环境搭建
Windows 系统上推荐使用这种方式。现在的操作系统基本上都是 64 位的,所以选择 64 位的 go1.15.windows-amd64.msi 下载即可,如果操作系统是 32 位的,选择 go1.15.windows-386.msi 进行下载。
PayneWu
2020/12/18
2.4K0
Golang开发环境搭建
常见编程语言对REPL支持情况小结
最近跟一个朋友聊起编程语言的一些特性,他有个言论让我略有所思:“不能REPL的都是渣”。当然这个观点有点偏激,但我们可以探究一下,我们常用的编程语言里面,哪些支持REPL,哪些不支持,还有REPL的一些概况。 在一般的脚本语言中,有REPL是常态, 因为REPL非常的方便。 编程术语 REPL (Read-Eval-Print Loop) 中文的话有翻译成“交互式解释器”或“交互式编程环境”的。 不过我觉得不用翻译,直接REPL就好了,这样的术语,翻译成中文后,读者更难理解。下面是对 REPL 的解
Albert陈凯
2018/04/04
1.7K0
跨平台构建 Docker 镜像新姿势,x86、arm 一把梭
在工作和生活中,我们可能经常需要将某个程序跑在不同的 CPU 架构上,比如让某些不可描述的软件运行在树莓派或嵌入式路由器设备上。特别是 Docker 席卷全球之后,我们可以轻松地在 ARM 设备上通过容器部署各种好玩的应用,而不用在意各种系统的差异性。
米开朗基杨
2019/11/25
43.6K1
跨平台构建 Docker 镜像新姿势,x86、arm 一把梭
Go语言环境搭建详解
最近写了很多Go语言的原创文章,其中Go语言实战系列30篇,近15W字,还有最近更新的Go经典库系列,不过通过大家的咨询来看,还是想要一些入门的知识,这一篇文章写于2017年初,这里再更新一下,发给大家。
飞雪无情
2018/08/28
9740
golang调用python3,并使用python模块中的方法
因项目需要,很多代码和python模块是go语言没有的,虽然有个项目是转化python代码到golang代码,但是还没开始用,关键是python引用的模块如此之多,不可能都去转换对吧。
hotqin888
2022/03/10
4K0
golang调用python3,并使用python模块中的方法
Linux编译C++
1)此时脚本开始运行 2)选择python3解释编译ycm文件 此时脚本文件会问你是选择python2还是python3来编译ycm文件?我在这里选择3,在此之前请安装python3 3)开始安装插件 4)此时vimplus就安装成功了
承苏凯
2020/07/24
24.3K0
M1 Mac上更好的 Golang 使用方案
本篇文章,将分享如何在苹果 M1 Mac 设备上,来进行高效、可靠的 Golang 开发环境的安装和管理。
soulteary
2022/05/12
1.4K0
M1 Mac上更好的 Golang 使用方案
PsySH——PHP交互式控制台
[导读] 今天在Github上发现了一个挺有意思的PHP项目:PsySH。 百度了一番,发现没有任何关于它的中文文章,经过研究,决定写本篇博文来讲述一下。 如果对你有所帮助,请留下你的回复 PsySH is a runtime developer console, interactive debugger and REPL for PHP. PsySH是一个PHP的运行时开发平台,交互式调试器和Read-Eval-Print Loop (REPL)。 说的简单点,就像你用firebug的console调试
wangxl
2018/03/08
2.3K0
PsySH——PHP交互式控制台
Open Policy Agent(OPA) 入门实践
本篇我来为你介绍一个我个人很喜欢的,通用策略引擎,名叫 OPA,全称是 Open Policy Agent。
Jintao Zhang
2021/12/09
2.6K0
Open Policy Agent(OPA) 入门实践
Go 包概念及其机制详解&内置工具使用简介 【Go语言圣经笔记】
现在随便一个小程序的实现都可能包含超过10000个函数。然而作者一般只需要考虑其中很小的一部分和做很少的设计,因为绝大部分代码都是由他人编写的,它们通过类似包或模块的方式被重用。
Steve Wang
2021/12/06
1.7K0
Go 包概念及其机制详解&内置工具使用简介 【Go语言圣经笔记】
Go语言环境搭建详解(2020版)
最近写了很多Go语言的原创文章,其中Go语言实战系列30篇,近15W字,还有最近更新的Go经典库系列,不过通过大家的咨询来看,还是想要一些入门的知识,这一篇文章写于2017年初,这3年多Go更新了很多版本,所以需要更新下这篇文章。
飞雪无情
2020/11/05
6.5K0
我在暴躁同事小张的胁迫下学会了Go的交叉编译和条件编译
今天继续关于Go开发经验的分享,这次的主题是关于Go的交叉编译和条件编译,伴随着我对自己打不过、惹不起的壕同事小张还有运维们的碎碎念。
KevinYan
2020/09/27
2.8K0
我在暴躁同事小张的胁迫下学会了Go的交叉编译和条件编译
云原生(三十) | Kubernetes篇之应用商店-Helm介绍
​应用商店-Helm一、简介二、安装1、用二进制版本安装每个Helm版本都提供了各种操作系统的二进制版本,这些版本可以手动下载和安装。 下载 需要的版本 解压(tar -zxvf helm-v3.0.0-linux-amd64.tar.gz) 在解压目中找到helm程序,移动到需要的目录中(mv linux-amd64/helm /usr/local/bin/helm) #!/usr/bin/env bash# Copyright The Helm Authors.## Licensed under
Lansonli
2022/07/12
8180
云原生(三十) | Kubernetes篇之应用商店-Helm介绍
相关推荐
Go语言实战笔记(二)| Go开发工具
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档