Spring Security内置过滤器的维护方法
作者:码农小胖哥 发布时间:2022-07-30 18:10:16
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谁就越靠前。
来源:https://developer.51cto.com/article/702180.html
猜你喜欢
- 一个非侵入的api编译、收集、Rest文档生成工具。工具通过分析代码和注释,获取文档信息,生成RestDoc文档前言程序员一直以来都有一个烦
- 一,使用注解: 在spring的配置文件applicationContext.xml中,加入注解扫描。配
- 一个是新浪微博,腾讯微博的分享按钮,一个是他们的绑定情况(其实就是是否授权)。点击微博分享中新浪或腾讯按钮,就进行相应的授权(若没授权),显
- 推荐教程IntelliJ IDEA 2020最新激活码(亲测有效,可激活至 2089 年)最新idea2021注册码永久激活(激活到2100
- 1. strlen —— 求字符串长度1.1 strlen 的声明与用处strlen ,我们有一些英
- jwt简介冒泡排序:(Bubble Sort)是一种简单的交换排序。之所以叫做冒泡排序,因为我们可以把每个元素当成一个小气泡,根据气泡大小,
- 本文实例为大家分享了Java解码H264格式视频流中的图片,供大家参考,具体内容如下引入依赖<dependency>  
- Spring整合mybatis的mapper生成过程mapperScannerConfigurer实现了BeandifinitionRegi
- mybatis insert foreach循环插入@Insert("<script>" +
- 1、安装依赖<dependency> <
- 截取字符串最后一位1.用substring()来截取理论上它是按照字符串.substring(字符串.lastIndexOf("\
- 今天重新装了编译器,结果崩无极限,真是日了狗了了。刚刚才知道问题在哪边。好了,说正事,对于ios开发我没接触,不是很了解,百度了半天,差不多
- 一、Spring Bean 集合注入在【Spring学习笔记(三)】已经讲了怎么注入基本数据类型和引用数据类型,接下来介绍如何注入比较特殊的
- 多数据源创建数据库CREATE DATABASE mybatis_plus_1;USE mybatis_plus_1;CREATE TABL
- spring mvc @PathVariable / 带斜杠方式获取遇上这个问题,百度google了一下,抄袭里面的内容,可以实现,在此备忘
- Spring boot默认使用的是SimpleCacheConfiguration,即使用ConcurrentMapCacheManager
- 本文实例讲述了Java设计模式之工厂模式实现方法。分享给大家供大家参考,具体如下:工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体
- 在POI的使用过程中,对大多数API User来说经常面临两个问题,这也是GridExcel致力解决的问题。问题1. 仅使用简单的导入导出功
- 请求SpringBoot接受前台参数的六种方式,首先因为从前台发送的请求没有界面的话只能是从地址栏发送并且只能是Get请求,为了测试其他的请
- 需求描述:企业开发过程中,经常需要将一些静态文本数据放到Resources目录下,项目启动时或者程序运行