Spring Security注冊過濾器注意事項(xiàng)詳解
一 問題復(fù)原
先來說問題吧,在 Spring Security+JWT 登錄中,整體上的思路就是用戶登錄成功之后返回 JWT 字符串,然后以后用戶每次請求都攜帶上 JWT 字符串,服務(wù)端進(jìn)行校驗(yàn),校驗(yàn)通過之后,請求繼續(xù)執(zhí)行。
按照上面的思路,我們的項(xiàng)目中需要有一個(gè) JwtFilter 用來從請求中提取請求傳來的 Jwt 字符串進(jìn)行校驗(yàn),類似下面這樣:
@Component public class JwtFilter extends GenericFilterBean { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) servletRequest; String requestURI = req.getRequestURI(); if ("/login".equals(requestURI)) { //登錄請求,無需校驗(yàn)令牌,請求繼續(xù)執(zhí)行 filterChain.doFilter(xxx,xxx); return; } //令牌校驗(yàn) } }
然后有一個(gè)小伙伴反饋,在項(xiàng)目中使用了 WebSecurityCustomizer 給 Swagger 相關(guān)的請求都放行了,結(jié)果這些被放行的請求都被 JwtFilter 攔截了,這是咋回事呢?
首先小伙伴們要知道,使用 WebSecurityCustomizer 放行的請求,都不再經(jīng)過 SecurityFilter 了,所以按理不該再被 JwtFilter 攔截了,因?yàn)?JwtFilter 是隸屬于 SecurityFilter 這個(gè)過濾器鏈中的,并非原生的跟 Servlet 平級的那種 Filter。
但是為什么又?jǐn)r截了呢?
松哥看了下代碼,發(fā)現(xiàn)問題出在 @Component 這個(gè)注解上。
二 原理分析
在 Spring Boot 項(xiàng)目啟動的時(shí)候,有一個(gè)環(huán)節(jié)就是把 Spring 容器中所有類型為 Filter 的 Bean 找出來,并且自動添加到容器的過濾器鏈條中(注意不是添加到 Spring Security 過濾器鏈中)。
這段代碼的邏輯位于 ServletContextInitializerBeans#addAdaptableBeans 方法中,在該方法中,會調(diào)用 addAsRegistrationBean 方法完成以上事情:
private <T, B extends T> void addAsRegistrationBean(ListableBeanFactory beanFactory, Class<T> type, Class<B> beanType, RegistrationBeanAdapter<T> adapter) { List<Map.Entry<String, B>> entries = getOrderedBeansOfType(beanFactory, beanType, this.seen); for (Entry<String, B> entry : entries) { String beanName = entry.getKey(); B bean = entry.getValue(); if (this.seen.add(bean)) { // One that we haven't already seen RegistrationBean registration = adapter.createRegistrationBean(beanName, bean, entries.size()); int order = getOrder(bean); registration.setOrder(order); this.initializers.add(type, registration); } } }
可以看到,這里傳入的參數(shù) type 和 beanType 都是 Filter,從 Spring 容器中找到 Filter 類型的 Bean 存入到 initializers 集合中。不過注意,添加到集合中的實(shí)際上是封裝之后的 registration 對象,這個(gè)對象通過 adapter.createRegistrationBean
方法創(chuàng)建出來,在該方法中,由于我們沒有為當(dāng)前過濾器設(shè)置攔截的請求地址,所以默認(rèn)攔截所有請求,攔截規(guī)則是 /*
。
最后在 ServletWebServerApplicationContext#selfInitialize 方法中遍歷上一步找到的過濾器,并逐個(gè)進(jìn)行配置,相關(guān)代碼如下:
DynamicRegistrationBean#register:
@Override protected final void register(String description, ServletContext servletContext) { //注冊過濾器 D registration = addRegistration(description, servletContext); //省略 }
AbstractFilterRegistrationBean#addRegistration:
@Override protected Dynamic addRegistration(String description, ServletContext servletContext) { Filter filter = getFilter(); return servletContext.addFilter(getOrDeduceName(filter), filter); }
可以看到,這最終就是大家熟知的添加過濾器的代碼了。
三 解決方案
找到問題的原因,那么問題就好解決了。
問題的產(chǎn)生,主要是因?yàn)?Spring 自動查找容器中所有 Filter 類型的 Bean,并進(jìn)行配置,那么我們的解決方案就是不要把這個(gè) Bean 注冊到 Spring 容器中,即不要添加 @Component 注解,而是直接自己 new 出來就行了,在配置過濾器鏈的時(shí)候,像下面這樣配置即可:
http.addFilterAfter(new JwtFilter(redisTemplate), SecurityContextHolderFilter.class);
經(jīng)過上面這樣配置之后,JwtFilter 就不存在于原生過濾器鏈中了,只是單純的存在于 SecurityFilter 中。
理解了 Spring Security 原理,那么日常開發(fā)中各種奇奇怪怪的情況,我們就都能輕車熟路的解決了。
到此這篇關(guān)于Spring Security注冊過濾器注意事項(xiàng)詳解的文章就介紹到這了,更多相關(guān)Spring Security注冊過濾器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring?Native打包本地鏡像的操作方法(無需通過Graal的maven插件buildtools)
這篇文章主要介紹了Spring?Native打包本地鏡像,無需通過Graal的maven插件buildtools,本文探索一下,如果不通過這個(gè)插件來生成鏡像,結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-02-02Java Scanner輸入兩個(gè)數(shù)組的方法
今天小編就為大家分享一篇Java Scanner輸入兩個(gè)數(shù)組的方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-07-07一次Jvm old過高的排查過程實(shí)戰(zhàn)記錄
這篇文章主要給大家介紹了一次Jvm old過高的排查過程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-11-11JDK基于CAS實(shí)現(xiàn)原子類盤點(diǎn)解析
這篇文章主要為大家介紹了JDK基于CAS實(shí)現(xiàn)原子類盤點(diǎn)解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12java中建立0-10m的消息(字符串)實(shí)現(xiàn)方法
下面小編就為大家?guī)硪黄猨ava中建立0-10m的消息(字符串)實(shí)現(xiàn)方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-05-05