Spring?Security內(nèi)置過濾器的維護方法
Spring Security中的內(nèi)置過濾器順序是怎么維護的?我想很多開發(fā)者都對這個問題感興趣。本篇我和大家一起探討下這個問題。
HttpSecurity包含了一個成員變量FilterOrderRegistration,這個類是一個內(nèi)置過濾器注冊表。至于這些過濾器的作用,不是本文介紹的重點,有興趣可以去看看FilterOrderRegistration的源碼。
內(nèi)置過濾器的順序
FilterOrderRegistration維護了一個變量filterToOrder,它記錄了類之間的順序和上下之間的間隔步長。我們復制了一個FilterOrderRegistration來直觀感受一下過濾器的順序:
CopyFilterOrderRegistration filterOrderRegistration = new CopyFilterOrderRegistration();
// 獲取內(nèi)置過濾器 此方法并未提供
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 ));打印結果:

我們可以看得出內(nèi)置過濾器之間的位置是相對固定的,除了第一個跟第二個步長為200外,其它步長為100。
內(nèi)置過濾器并非一定會生效,僅僅是預置了它們的排位,需要通過HttpSecurity的addFilterXXXX系列方法顯式添加才行。
注冊過濾器的邏輯
FilterOrderRegistration提供了一個put方法:
void put(Class<? extends Filter> filter, int position) {
String className = filter.getName();
// 如果這個類已經(jīng)注冊就忽略
if (this.filterToOrder.containsKey(className)) {
return;
}
// 如果沒有注冊就注冊順序。
this.filterToOrder.put(className, position);
}從這個方法我們可以得到幾個結論:
- 內(nèi)置的34個過濾器是有固定序號的,不可被改變。
- 新加入的過濾器的類全限定名是不能和內(nèi)置過濾器重復的。
- 新加入的過濾器的順序是可以和內(nèi)置過濾器的順序重復的。
獲取已注冊過濾器的順序值
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的內(nèi)置私有方法。Filter是想要注冊到DefaultSecurityFilterChain中的過濾器,offset是向右的偏移值,registeredFilter是已經(jīng)注冊到FilterOrderRegistration的過濾器,而且registeredFilter沒有注冊的話會空指針。
private HttpSecurity addFilterAtOffsetOf(Filter filter, int offset, Class<? extends Filter> registeredFilter) {
// 首先會根據(jù)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僅僅是偏移值的區(qū)別,這里不再贅述。
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必須是已經(jīng)注冊到FilterOrderRegistration的Filter,這意味著它可能是內(nèi)置的Filter,也可能是先前通過addFilterBefore、addFilterAt或者addFilterAfter注冊的非內(nèi)置Filter。
問題來了
之前看到一個問題,如果HttpSecurity注冊兩個重復序號的Filter會是怎么樣的順序呢?我們先來看下排序的機制:
// filters private List<OrderedFilter> filters = new ArrayList<>(); //排序 this.filters.sort(OrderComparator.INSTANCE);
看了下OrderComparator源碼,其實還是通過數(shù)字的自然排序,數(shù)字越小越靠前。如果數(shù)字相同,索引越小越靠前。也就是同樣的序號,誰先add到filters誰就越靠前。
到此這篇關于Spring Security的內(nèi)置過濾器是如何維護的的文章就介紹到這了,更多相關Spring Security內(nèi)置過濾器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
SpringBoot + SpringSecurity 短信驗證碼登錄功能實現(xiàn)
這篇文章主要介紹了SpringBoot + SpringSecurity 短信驗證碼登錄功能實現(xiàn),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-06-06
Java ScheduledExecutorService的具體使用
ScheduledExecutorService有線程池的特性,也可以實現(xiàn)任務循環(huán)執(zhí)行,本文主要介紹了Java ScheduledExecutorService的具體使用,具有一定的參考價值,感興趣的可以了解一下2023-05-05
詳解static 和 final 和 static final區(qū)別
這篇文章主要介紹了static 和 final 和 static final區(qū)別,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-04-04
Java調(diào)用Pytorch模型實現(xiàn)圖像識別
這篇文章主要為大家詳細介紹了Java如何調(diào)用Pytorch實現(xiàn)圖像識別功能,文中的示例代碼講解詳細,具有一定的學習價值,感興趣的小伙伴可以了解一下2023-06-06
Spring事務注解@Transactional失效的八種場景分析
最近在開發(fā)采用Spring框架的項目中,使用了@Transactional注解,但發(fā)現(xiàn)事務注解失效了,所以這篇文章主要給大家介紹了關于Spring事務注解@Transactional失效的八種場景,需要的朋友可以參考下2021-05-05

