Spring Security的内置过滤器是如何维护的
2022年的开工福利已经发布,点击下面按钮获取最新PDF。
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
谁就越靠前。
附DEMO| 绝活!Spring Security过滤器就该这么配置
OAuth2授权服务器Keycloak宣布不再适配Spring Boot和Spring Security
通过以下公众号回复 2022开工福利 就可以获得原创PDF
文章来源: felord.blog.csdn.net,作者:码农小胖哥,版权归原作者所有,如需转载,请联系作者。
原文链接:felord.blog.csdn.net/article/details/123059346
- 点赞
- 收藏
- 关注作者
评论(0)