溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

如何分析Spring Security中過(guò)濾器鏈的配置問(wèn)題

發(fā)布時(shí)間:2021-12-02 15:57:14 來(lái)源:億速云 閱讀:337 作者:柒染 欄目:大數(shù)據(jù)

如何分析Spring Security中過(guò)濾器鏈的配置問(wèn)題,相信很多沒(méi)有經(jīng)驗(yàn)的人對(duì)此束手無(wú)策,為此本文總結(jié)了問(wèn)題出現(xiàn)的原因和解決方法,通過(guò)這篇文章希望你能解決這個(gè)問(wèn)題。

首先這個(gè)問(wèn)題本身是有點(diǎn)問(wèn)題的,因?yàn)?http.authorizeRequests() 并非總是第一個(gè),雖然大部分情況下,我們看到的是第一個(gè),但是也有很多情況 http.authorizeRequests() 不是首先出現(xiàn)。要搞明白這個(gè)問(wèn)題,我們就要搞清楚 http.authorizeRequests() 到底是啥意思!

這就涉及到 Spring Security 中過(guò)濾器鏈的配置問(wèn)題

 

1.從過(guò)濾器開(kāi)始

即使大家沒(méi)有仔細(xì)研究過(guò) Spring Security 中認(rèn)證、授權(quán)功能的實(shí)現(xiàn)機(jī)制,大概也都多多少少聽(tīng)說(shuō)過(guò) Spring Security 這些功能是通過(guò)過(guò)濾器來(lái)實(shí)現(xiàn)的。

是的,沒(méi)錯(cuò)!Spring Security 中一共提供了 32 個(gè)過(guò)濾器,其中默認(rèn)使用的有 15 個(gè),這些過(guò)濾器松哥在以后的文章中再和大家細(xì)說(shuō),今天我們就先來(lái)看看過(guò)濾器的配置問(wèn)題。

在一個(gè) Web 項(xiàng)目中,請(qǐng)求流程大概如下圖所示:

如何分析Spring Security中過(guò)濾器鏈的配置問(wèn)題  

請(qǐng)求從客戶(hù)端發(fā)起(例如瀏覽器),然后穿過(guò)層層 Filter,最終來(lái)到 Servlet 上,被 Servlet 所處理。

那有小伙伴要問(wèn)了,Spring Security 中默認(rèn)的 15 個(gè)過(guò)濾器就是這樣嵌套在 Client 和 Servlet 之間嗎?

不是的!

上圖中的 Filter 我們可以稱(chēng)之為 Web Filter,Spring Security 中的 Filter 我們可以稱(chēng)之為 Security Filter,它們之間的關(guān)系如下圖:

如何分析Spring Security中過(guò)濾器鏈的配置問(wèn)題  

可以看到,Spring Security Filter 并不是直接嵌入到 Web Filter 中的,而是通過(guò) FilterChainProxy 來(lái)統(tǒng)一管理 Spring Security Filter,F(xiàn)ilterChainProxy 本身則通過(guò) Spring 提供的 DelegatingFilterProxy 代理過(guò)濾器嵌入到 Web Filter 之中。

?  

DelegatingFilterProxy 很多小伙伴應(yīng)該比較熟悉,在 Spring 中手工整合 Spring Session、Shiro 等工具時(shí)都離不開(kāi)它,現(xiàn)在用了 Spring Boot,很多事情 Spring Boot 幫我們做了,所以有時(shí)候會(huì)感覺(jué) DelegatingFilterProxy 的存在感有所降低,實(shí)際上它一直都在。

 

2.多個(gè)過(guò)濾器鏈

上面和大家介紹的是單個(gè)過(guò)濾器鏈,實(shí)際上,在 Spring Security 中,可能存在多個(gè)過(guò)濾器鏈。

在松哥前面講 OAuth3 系列的時(shí)候,有涉及到多個(gè)過(guò)濾器鏈,但是一直沒(méi)有拎出來(lái)單獨(dú)講過(guò),今天就來(lái)和大家分享一下。

有人會(huì)問(wèn),下面這種配置是不是就是多個(gè)過(guò)濾器鏈?

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
            .antMatchers("/admin/**").hasRole("admin")
            .antMatchers("/user/**").hasRole("user")
            .anyRequest().authenticated()
            ...
            .csrf().disable();
}
 

這樣的配置相信大家都見(jiàn)過(guò),但是這并不是多個(gè)過(guò)濾器鏈,這是一個(gè)過(guò)濾器鏈。因?yàn)椴还苁?/admin/** 還是 /user/** ,走過(guò)的過(guò)濾器都是一樣的,只是不同的路徑判斷條件不一樣而已。

如果系統(tǒng)存在多個(gè)過(guò)濾器鏈,多個(gè)過(guò)濾器鏈會(huì)在 FilterChainProxy 中進(jìn)行劃分,如下圖:

如何分析Spring Security中過(guò)濾器鏈的配置問(wèn)題  

可以看到,當(dāng)請(qǐng)求到達(dá) FilterChainProxy 之后,F(xiàn)ilterChainProxy 會(huì)根據(jù)請(qǐng)求的路徑,將請(qǐng)求轉(zhuǎn)發(fā)到不同的 Spring Security Filters 上面去,不同的 Spring Security Filters 對(duì)應(yīng)了不同的過(guò)濾器,也就是不同的請(qǐng)求將經(jīng)過(guò)不同的過(guò)濾器。

正常情況下,我們配置的都是一個(gè)過(guò)濾器鏈,多個(gè)過(guò)濾器鏈怎么配置呢?松哥給大家一個(gè)舉一個(gè)簡(jiǎn)單的例子:

@Configuration
public class SecurityConfig {
    @Bean
    protected UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("javaboy").password("{bcrypt}$2a$10$Sb1gAUH4wwazfNiqflKZve4Ubh.spJcxgHG8Cp29DeGya5zsHENqi").roles("admin", "aaa", "bbb").build());
        manager.createUser(User.withUsername("sang").password("{noop}123").roles("admin").build());
        manager.createUser(User.withUsername("江南一點(diǎn)雨").password("{MD5}{Wucj/L8wMTMzFi3oBKWsETNeXbMFaHZW9vCK9mahMHc=}4d43db282b36d7f0421498fdc693f2a2").roles("user", "aaa", "bbb").build());
        return manager;
    }

    @Configuration
    @Order(1)
    static class DefaultWebSecurityConfig extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.antMatcher("/foo/**")
                    .authorizeRequests()
                    .anyRequest().hasRole("admin")
                    .and()
                    .csrf().disable();
        }
    }

    @Configuration
    @Order(2)
    static class DefaultWebSecurityConfig2 extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.antMatcher("/bar/**")
                    .authorizeRequests()
                    .anyRequest().hasRole("user")
                    .and()
                    .formLogin()
                    .permitAll()
                    .and()
                    .csrf().disable();
        }
    }
}
 
  1. 首先,SecurityConfig 不再需要繼承自 WebSecurityConfigurerAdapter 了,只是作為一個(gè)普通的配置類(lèi),加上 @Configuration 注解即可。
  2. 提供 UserDetailsService 實(shí)例,相當(dāng)于是我們的數(shù)據(jù)源。
  3. 創(chuàng)建靜態(tài)內(nèi)部類(lèi)繼承 WebSecurityConfigurerAdapter 類(lèi),同時(shí)用 @Configuration 注解標(biāo)記靜態(tài)內(nèi)部類(lèi)是一個(gè)配置類(lèi),配置類(lèi)里邊的代碼就和之前的一樣了,無(wú)需贅述。
  4. 每一個(gè)靜態(tài)內(nèi)部類(lèi)相當(dāng)于就是一個(gè)過(guò)濾器鏈的配置。
  5. 注意在靜態(tài)內(nèi)部類(lèi)里邊,我沒(méi)有使用     http.authorizeRequests() 開(kāi)始,     http.authorizeRequests() 配置表示該過(guò)濾器鏈過(guò)濾的路徑是     /**。在靜態(tài)內(nèi)部類(lèi)里邊,我是用了     http.antMatcher("/bar/**") 開(kāi)啟配置,表示將當(dāng)前過(guò)濾器鏈的攔截范圍限定在     /bar/**。
  6. 當(dāng)存在多個(gè)過(guò)濾器鏈的時(shí)候,必然會(huì)有一個(gè)優(yōu)先級(jí)的問(wèn)題,所以每一個(gè)過(guò)濾器鏈的配置類(lèi)上通過(guò) @Order(2) 注解來(lái)標(biāo)記優(yōu)先級(jí)。

從上面這段代碼中大家可以看到,configure(HttpSecurity http) 方法似乎就是在配置過(guò)濾器鏈?是的沒(méi)錯(cuò)!我們?cè)谠摲椒ㄖ械呐渲?,都是在添?移除/修改 Spring Security 默認(rèn)提供的過(guò)濾器,所以該方法就是在配置 Spring Security 中的過(guò)濾器鏈,至于是怎么配置的,松哥以后抽時(shí)間再來(lái)和大家細(xì)說(shuō)。

 

3.回到問(wèn)題

最后,我們?cè)诨氐揭婚_(kāi)始小伙伴提的問(wèn)題。

首先,http.authorizeRequests() 配置并非總在第一行出現(xiàn),如果只有一個(gè)過(guò)濾器鏈,他總是在第一行出現(xiàn),表示該過(guò)濾器鏈的攔截規(guī)則是 /**請(qǐng)求只有先被過(guò)濾器鏈攔截下來(lái),接下來(lái)才會(huì)進(jìn)入到不同的 Security Filters 中進(jìn)行處理),如果存在多個(gè)過(guò)濾器鏈,就不一定了。

僅僅從字面意思來(lái)理解,authorizeRequests() 方法的返回值是 ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry,ExpressionUrlAuthorizationConfigurer 可以為多組不同的 RequestMatcher 配置不同的權(quán)限規(guī)則,就是大家看到的 .antMatchers("/admin/**").hasRole("admin").antMatchers("/user/**").hasRole("user")。

看完上述內(nèi)容,你們掌握如何分析Spring Security中過(guò)濾器鏈的配置問(wèn)題的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI