Spring?Security內(nèi)置過濾器的維護(hù)方法
Spring Security中的內(nèi)置過濾器順序是怎么維護(hù)的?我想很多開發(fā)者都對這個(gè)問題感興趣。本篇我和大家一起探討下這個(gè)問題。
HttpSecurity包含了一個(gè)成員變量FilterOrderRegistration,這個(gè)類是一個(gè)內(nèi)置過濾器注冊表。至于這些過濾器的作用,不是本文介紹的重點(diǎn),有興趣可以去看看FilterOrderRegistration的源碼。
內(nèi)置過濾器的順序
FilterOrderRegistration維護(hù)了一個(gè)變量filterToOrder,它記錄了類之間的順序和上下之間的間隔步長。我們復(fù)制了一個(gè)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 ));
打印結(jié)果:
我們可以看得出內(nèi)置過濾器之間的位置是相對固定的,除了第一個(gè)跟第二個(gè)步長為200外,其它步長為100。
內(nèi)置過濾器并非一定會(huì)生效,僅僅是預(yù)置了它們的排位,需要通過HttpSecurity的addFilterXXXX系列方法顯式添加才行。
注冊過濾器的邏輯
FilterOrderRegistration提供了一個(gè)put方法:
void put(Class<? extends Filter> filter, int position) { String className = filter.getName(); // 如果這個(gè)類已經(jīng)注冊就忽略 if (this.filterToOrder.containsKey(className)) { return; } // 如果沒有注冊就注冊順序。 this.filterToOrder.put(className, position); }
從這個(gè)方法我們可以得到幾個(gè)結(jié)論:
- 內(nèi)置的34個(gè)過濾器是有固定序號的,不可被改變。
- 新加入的過濾器的類全限定名是不能和內(nèi)置過濾器重復(fù)的。
- 新加入的過濾器的順序是可以和內(nèi)置過濾器的順序重復(fù)的。
獲取已注冊過濾器的順序值
FilterOrderRegistration還提供了一個(gè)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維護(hù)過濾器的方法
接下來我們分析一下HttpSecurity維護(hù)過濾器的幾個(gè)方法。
addFilterAtOffsetOf
addFilterAtOffsetOf是一個(gè)HttpSecurity的內(nèi)置私有方法。Filter是想要注冊到DefaultSecurityFilterChain中的過濾器,offset是向右的偏移值,registeredFilter是已經(jīng)注冊到FilterOrderRegistration的過濾器,而且registeredFilter沒有注冊的話會(huì)空指針。
private HttpSecurity addFilterAtOffsetOf(Filter filter, int offset, Class<? extends Filter> registeredFilter) { // 首先會(huì)根據(jù)registeredFilter的順序和偏移值來計(jì)算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; }
務(wù)必記著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。
問題來了
之前看到一個(gè)問題,如果HttpSecurity注冊兩個(gè)重復(fù)序號的Filter會(huì)是怎么樣的順序呢?我們先來看下排序的機(jī)制:
// filters private List<OrderedFilter> filters = new ArrayList<>(); //排序 this.filters.sort(OrderComparator.INSTANCE);
看了下OrderComparator源碼,其實(shí)還是通過數(shù)字的自然排序,數(shù)字越小越靠前。如果數(shù)字相同,索引越小越靠前。也就是同樣的序號,誰先add到filters誰就越靠前。
到此這篇關(guān)于Spring Security的內(nèi)置過濾器是如何維護(hù)的的文章就介紹到這了,更多相關(guān)Spring Security內(nèi)置過濾器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot+Quartz實(shí)現(xiàn)動(dòng)態(tài)定時(shí)任務(wù)
這篇文章主要為大家詳細(xì)介紹了springBoot+Quartz實(shí)現(xiàn)動(dòng)態(tài)定時(shí)任務(wù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-09-09java實(shí)現(xiàn)Spring在XML配置java類的方法
下面小編就為大家?guī)硪黄猨ava實(shí)現(xiàn)Spring在XML配置java類的方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-11-11深入Spring Boot之ClassLoader的繼承關(guān)系和影響
這篇文章主要介紹了深入Spring Boot之ClassLoader的繼承關(guān)系和影響,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-06-06Java微信授權(quán)登陸的實(shí)現(xiàn)示例
微信授權(quán)登錄,官方文檔寫的比較簡潔。所以對于會(huì)的人一目了然,而對于新手剛?cè)腴T的人來說是舉步維艱。本文詳細(xì)的介紹了Java微信授權(quán)登陸的實(shí)現(xiàn)示例,感興趣的朋友可以了解一下2021-06-06Java Web實(shí)現(xiàn)文件上傳和下載接口功能詳解
這篇文章主要為大家詳細(xì)介紹了Java Web實(shí)現(xiàn)文件上傳和下載接口功能的相關(guān)知識,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)有一定的借鑒價(jià)值,需要的可以參考一下2022-12-12Java String字符串補(bǔ)0或空格的實(shí)現(xiàn)代碼
這篇文章主要介紹了Java String字符串補(bǔ)0或空格的實(shí)現(xiàn)代碼,代碼簡單易懂,非常不錯(cuò),具有參考借鑒價(jià)值,感興趣的朋友一起看看吧2016-09-09