最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringSecurity實(shí)現(xiàn)原理及多過(guò)濾器鏈匹配規(guī)則詳解

 更新時(shí)間:2025年10月21日 14:19:06   作者:henry_yang2018  
SpringSecurity通過(guò)FilterChainProxy管理多個(gè)過(guò)濾器鏈,根據(jù)請(qǐng)求的URI和RequestMatcher匹配,選擇合適的過(guò)濾器鏈進(jìn)行認(rèn)證和授權(quán)處理,配置多個(gè)過(guò)濾器鏈需用@Order區(qū)分優(yōu)先級(jí),處理流程清晰高效

SpringSecurity的實(shí)現(xiàn)原理

Spring Security能完成各種認(rèn)證和授權(quán)功能其實(shí)是依賴(lài)其底層的多個(gè)過(guò)濾器進(jìn)行實(shí)現(xiàn)的,

借用官方的一張?jiān)韴D如下:

但是實(shí)際上這些Filter并不是直接配置在tomcat中,其實(shí)他們都由一個(gè)叫做FilterChainProxy的類(lèi)進(jìn)行管理

這些Filter包括Spring Security默認(rèn)生成的以及我們自己自定義的,通通都被封裝成成一個(gè)個(gè)FilterChain并且保存在FilterChainProxy的一個(gè)成員變量中,一個(gè)FilterChain包含多個(gè)Filter,

FilterChainProxy包含多個(gè)FilterChain

原理圖和代碼如下:

public class FilterChainProxy extends GenericFilterBean {
    private static final Log logger = LogFactory.getLog(FilterChainProxy.class);
    private static final String FILTER_APPLIED =                FilterChainProxy.class.getName().concat(".APPLIED");
    private List<SecurityFilterChain> filterChains; //多個(gè)過(guò)濾器鏈
    private FilterChainProxy.FilterChainValidator filterChainValidator;
    private HttpFirewall firewall;
}

當(dāng)一個(gè)請(qǐng)求過(guò)來(lái)的時(shí)候,Spring Security會(huì)根據(jù)規(guī)則匹配到第一個(gè)過(guò)濾器鏈,并使用它過(guò)濾該請(qǐng)求

這里又引申出一些問(wèn)題,既然存在多過(guò)濾鏈的情況,那么用戶(hù)怎么配置多個(gè)過(guò)濾鏈,并且SpringSecurity是怎么根據(jù)請(qǐng)求選擇相應(yīng)的過(guò)濾器鏈

如何配置多個(gè)過(guò)濾器鏈

其實(shí)配置多個(gè)過(guò)濾器鏈并不難,項(xiàng)目中每存在一個(gè)繼承了WebSecurityConfigurerAdapter類(lèi)的配置類(lèi),Spring Securiy就會(huì)生成一個(gè)過(guò)濾器鏈;

繼承ResourceServerConfigurerAdapter類(lèi)的配置類(lèi)也會(huì)對(duì)應(yīng)一個(gè)過(guò)濾器鏈,但是與繼承了WebSecurityConfigurerAdapter類(lèi)的配置類(lèi)不同,

多個(gè)繼承ResourceServerConfigurerAdapter類(lèi)的配置類(lèi)都共存于一個(gè)過(guò)濾器鏈中,也就是無(wú)論配置多少個(gè)ResourceServerConfigurerAdapter也僅僅存在一個(gè)對(duì)應(yīng)的過(guò)濾鏈。

同時(shí)需要注意的是,存在多個(gè)WebSecurityConfigurerAdapter配置類(lèi)的時(shí)候,需要用@Order進(jìn)行區(qū)分,代表了它們之間的優(yōu)先級(jí)

配置代碼如下

@Configuration
@Order(200)
public class DefaultWebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        System.out.println("DefaultWebSecurityConfig "+http);
    }
}


@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        System.out.println("WebSecurityConfig "+http);
    }
}


@Configuration
public class ResourceSecurityConfig {

    public static final String RESOURCE_ID = "resource-server";

    @Resource
    private ResourceServerTokenServices resourceServerTokenServices;

    @Configuration
    @EnableResourceServer
    public class FirstResourceConfig extends ResourceServerConfigurerAdapter{
        //配置token服務(wù)以及資源ID
        @Override
        public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
            resources.resourceId(RESOURCE_ID)
                    .tokenServices(resourceServerTokenServices);
        }

        //配置訪(fǎng)問(wèn)控制
        @Override
        public void configure(HttpSecurity http) throws Exception {
            System.out.println("FirstResourceConfig "+http);
                    http
                    .authorizeRequests()
                    .antMatchers("/**").access("#oauth2.hasScope('server')")
            ;
        }

    }

    @Configuration
    @EnableResourceServer
    public class SecondResourceConfig extends ResourceServerConfigurerAdapter{
        //配置token服務(wù)以及資源ID
        @Override
        public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
            resources.resourceId(RESOURCE_ID)
                    .tokenServices(resourceServerTokenServices);
        }

        //配置訪(fǎng)問(wèn)控制
        @Override
        public void configure(HttpSecurity http) throws Exception {
            System.out.println("SecondResourceConfig "+http);
                    http
                    .authorizeRequests()
                    .antMatchers("/**").access("#oauth2.hasScope('server')")
            ;
        }

    }




}

上面的代碼就是配置了三個(gè)過(guò)濾器鏈,最后一個(gè)雖然好像配置了兩個(gè)過(guò)濾器鏈,但是前面已經(jīng)說(shuō)過(guò)了ResourceServerConfigurerAdapter的配置類(lèi)其實(shí)都會(huì)被合并在同一個(gè)過(guò)濾器鏈

那我們?cè)趺粗赖牡拇_確存在三個(gè)過(guò)濾器鏈呢,過(guò)濾器鏈都存在FilterChainProxy的成員變量中,我們只要debug一下看看它的成員變量就知道了,如下圖:

每一個(gè)FilterChain都包含一個(gè)RequestMatcher,如下圖

實(shí)際上過(guò)濾器鏈的RequestMatcher是和我們的配置有關(guān)系,前面我們的配置都是使用了.authorizeRequests()方法,其實(shí)這個(gè)就是代表AnyRequestMatcher這個(gè)類(lèi)

我們改變一下配置可以看看RequestMatcher會(huì)有什么變化

@Configuration
@Order(200)
public class DefaultWebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        System.out.println("DefaultWebSecurityConfig "+http);
        http.antMatcher("/user")
                .authorizeRequests().anyRequest().permitAll()
                .and()
                .formLogin();
    }
}

我們把第一個(gè)配置類(lèi)的規(guī)則改變了,看看debug會(huì)發(fā)生什么變化

它變成了AntPathRequestMatcher,這里可以看出我們的配置會(huì)直接影響到SpringSecurity為我們選擇合適的過(guò)濾器鏈,如果改成上面的配置,其實(shí)就代表

DefaultWebSecurityConfig對(duì)應(yīng)的過(guò)濾器鏈只匹配/user的請(qǐng)求,而其他兩個(gè)過(guò)濾器鏈就是匹配/**的請(qǐng)求,雖然兩個(gè)過(guò)濾器鏈都是匹配相同的地址,

但是他們的優(yōu)先級(jí)不同,一般ResourceServerConfigurerAdapter類(lèi)默認(rèn)的優(yōu)先級(jí)是@Order(3),而WebSecurityConfigurerAdapter類(lèi)默認(rèn)是@Order(100)

優(yōu)先級(jí)的值越低就越先被匹配到,所以ResourceServerConfigurerAdapter會(huì)被先匹配到

如何匹配多個(gè)過(guò)濾器鏈

要知道SpringSecurity是怎樣匹配一個(gè)合適的過(guò)濾鏈,我們先看下面的代碼:

private List<Filter> getFilters(HttpServletRequest request) {
        Iterator var2 = this.filterChains.iterator();

        SecurityFilterChain chain;
        do {
            if (!var2.hasNext()) {
                return null;
            }

            chain = (SecurityFilterChain)var2.next();
        } while(!chain.matches(request)); //這里就是匹配過(guò)濾器鏈的方法

        return chain.getFilters();
    }

chain.matches()就是匹配一個(gè)過(guò)濾器鏈的方法,我們繼續(xù)進(jìn)入該方法:

public final class DefaultSecurityFilterChain implements SecurityFilterChain {
    private static final Log logger = LogFactory.getLog(DefaultSecurityFilterChain.class);
    private final RequestMatcher requestMatcher;
    private final List<Filter> filters;


    public boolean matches(HttpServletRequest request) {
        return this.requestMatcher.matches(request);//實(shí)際上是調(diào)用了requestMatcher的matches方法
    }
}

實(shí)際上是調(diào)用了RequestMatcher的matches方法,所以其實(shí)SpringSecurity在對(duì)一個(gè)請(qǐng)求選擇一個(gè)過(guò)濾器鏈,就是通過(guò)調(diào)用每個(gè)過(guò)濾器鏈的RequestMatcher進(jìn)行匹配

匹配到第一個(gè)成功的就是處理該請(qǐng)求的過(guò)濾器鏈

總結(jié)

所以我們可以得出SpringSecurity在處理一個(gè)請(qǐng)求的流程

1.獲取該Request的URI地址

2.遍歷所有FilterChain,并且用它的RequestMatcher匹配Request的URI地址

3.匹配到第一個(gè)合適的FilterChain,把該請(qǐng)求放到該過(guò)濾器鏈進(jìn)行處理

4.過(guò)濾器鏈中的每一個(gè)過(guò)濾器獲得請(qǐng)求,并對(duì)請(qǐng)求做相應(yīng)的處理

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • SpringBoot防止大量請(qǐng)求攻擊的實(shí)現(xiàn)

    SpringBoot防止大量請(qǐng)求攻擊的實(shí)現(xiàn)

    在有些特定的時(shí)候需要加上IP訪(fǎng)問(wèn)時(shí)間限制,防止一個(gè)IP多次訪(fǎng)問(wèn)請(qǐng)求,本文主要介紹了SpringBoot防止大量請(qǐng)求攻擊的實(shí)現(xiàn),感興趣的可以了解一下
    2021-11-11
  • 新手了解java基礎(chǔ)知識(shí)(二)

    新手了解java基礎(chǔ)知識(shí)(二)

    這篇文章主要介紹了Java基礎(chǔ)知識(shí),本文介紹了Java語(yǔ)言相關(guān)的基礎(chǔ)知識(shí)、歷史介紹、主要應(yīng)用方向等內(nèi)容,需要的朋友可以參考下,希望對(duì)你有所幫助
    2021-07-07
  • Java語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單FTP軟件 FTP遠(yuǎn)程文件管理模塊實(shí)現(xiàn)(10)

    Java語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單FTP軟件 FTP遠(yuǎn)程文件管理模塊實(shí)現(xiàn)(10)

    這篇文章主要為大家詳細(xì)介紹了Java語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單FTP軟件,F(xiàn)TP遠(yuǎn)程文件管理模塊的實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • 將JSON字符串?dāng)?shù)組轉(zhuǎn)對(duì)象集合方法步驟

    將JSON字符串?dāng)?shù)組轉(zhuǎn)對(duì)象集合方法步驟

    這篇文章主要給大家介紹了關(guān)于將JSON字符串?dāng)?shù)組轉(zhuǎn)對(duì)象集合的方法步驟,文中通過(guò)代碼示例介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-08-08
  • Java URL自定義私有網(wǎng)絡(luò)協(xié)議

    Java URL自定義私有網(wǎng)絡(luò)協(xié)議

    URI與URL的區(qū)別 一.先來(lái)序言一段 二.協(xié)議的自定義的理解 三.自定義協(xié)議與URL的關(guān)系 四.URL自定義私有協(xié)議實(shí)戰(zhàn) 五.后話(huà),自定義mineType解析器
    2016-04-04
  • kafka內(nèi)外網(wǎng)訪(fǎng)問(wèn)配置方式

    kafka內(nèi)外網(wǎng)訪(fǎng)問(wèn)配置方式

    這篇文章主要介紹了kafka內(nèi)外網(wǎng)訪(fǎng)問(wèn)配置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • Java死鎖代碼實(shí)例及產(chǎn)生死鎖必備的四個(gè)條件

    Java死鎖代碼實(shí)例及產(chǎn)生死鎖必備的四個(gè)條件

    這篇文章主要介紹了Java死鎖代碼實(shí)例及產(chǎn)生死鎖必備的四個(gè)條件,Java 發(fā)生死鎖的根本原因是,在申請(qǐng)鎖時(shí)發(fā)生了交叉閉環(huán)申請(qǐng),synchronized在開(kāi)發(fā)中最好不要嵌套使用,容易導(dǎo)致死鎖,需要的朋友可以參考下
    2024-01-01
  • Java抽象類(lèi)和抽象方法定義與用法實(shí)例詳解

    Java抽象類(lèi)和抽象方法定義與用法實(shí)例詳解

    這篇文章主要介紹了Java抽象類(lèi)和抽象方法定義與用法,結(jié)合實(shí)例形式詳細(xì)分析了Java抽象類(lèi)和抽象方法相關(guān)原理、定義、使用方法及操作注意事項(xiàng),需要的朋友可以參考下
    2019-11-11
  • 快速上手Java單元測(cè)試框架JUnit5

    快速上手Java單元測(cè)試框架JUnit5

    今天給大家?guī)?lái)的是關(guān)于Java單元測(cè)試的相關(guān)知識(shí),文章圍繞著Java單元測(cè)試框架JUnit5展開(kāi),文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • 使用Mybatis對(duì)數(shù)據(jù)庫(kù)進(jìn)行單表操作的實(shí)現(xiàn)示例

    使用Mybatis對(duì)數(shù)據(jù)庫(kù)進(jìn)行單表操作的實(shí)現(xiàn)示例

    這篇文章主要介紹了使用Mybatis對(duì)數(shù)據(jù)庫(kù)進(jìn)行單表操作的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08

最新評(píng)論

霍城县| 皮山县| 咸丰县| 滕州市| 慈利县| 右玉县| 镇平县| 东安县| 万源市| 湘西| 秦皇岛市| 高州市| 叶城县| 佛坪县| 古浪县| 藁城市| 沙田区| 三都| 岑巩县| 象州县| 石柱| 陆良县| 张家界市| 天门市| 格尔木市| 庄浪县| 吉水县| 博客| 商洛市| 桃江县| 南皮县| 惠来县| 松桃| 长汀县| 平江县| 斗六市| 泰宁县| 迁西县| 怀仁县| 海门市| 凤台县|