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

詳解HttpSecurity是如何組裝過濾器鏈的

 更新時間:2024年06月02日 08:56:05   作者:江南一點雨  
HttpSecurity 本質(zhì)上也是一個 SecurityBuilder,我們平時在 HttpSecurity 配置的各種東西,本質(zhì)上其實就是一個 xxxConfigure,這些 xxxConfigure 被 HttpSecurity 收集起來,本文將給大家介紹HttpSecurity是如何組裝過濾器鏈的,需要的朋友可以參考下

一 SecurityFilterChain

首先大伙都知道,Spring Security 里邊的一堆功能都是通過 Filter 來實現(xiàn)的,無論是認證、RememberMe Login、會話管理、CSRF 處理等等,各種功能都是通過 Filter 來實現(xiàn)的。

所以,我們配置 Spring Security,說白了其實就是配置這些 Filter。

以前舊版繼承自 WebSecurityConfigurerAdapter 類,然后重寫 configure 方法,利用 HttpSecurity 去配置過濾器鏈,這種寫法其實不太好理解,特別對于新手來說,可能半天整不明白到底配置了啥。

現(xiàn)在新版寫法我覺得更加合理,因為直接就是讓開發(fā)者自己去配置過濾器鏈,類似下面這樣:

@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    return http.build();
}

這樣開發(fā)者更容易理解,自己是在配置配置 SecurityFilter 過濾器鏈,因為就是要配置這樣一個 Bean。

SecurityFilterChain 是一個接口,這個接口只有一個實現(xiàn)類 DefaultSecurityFilterChain。

DefaultSecurityFilterChain 中有一個 requestMatcher,通過 requestMatcher 可以識別出來哪些請求需要攔截,攔截下來之后,經(jīng)由該類的另外一個屬性 filters 進行處理,這個 filters 中保存了我們配置的所有 Filter。

public final class DefaultSecurityFilterChain implements SecurityFilterChain {

	private final RequestMatcher requestMatcher;

	private final List<Filter> filters;

}

因此,在配置 SecurityFilterChain 這個 Bean 的時候,我們甚至可以按照如下方式來寫:

@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    return new DefaultSecurityFilterChain(new AntPathRequestMatcher("/**"));
}

這個配置就表示攔截所有請求,但是攔截下來之后,這些請求所經(jīng)過的過濾器為空,即攔截所有請求但是不做任何處理。

我們也可以為 DefaultSecurityFilterChain 對象去配置過濾器鏈,大家看到,它的構(gòu)造器可以傳入 Filter:

但是,Spring Security 過濾器數(shù)量有 30+,我們平日開發(fā)使用的也在 15 個左右,這樣一個一個去配置太麻煩了,每個過濾器并非 new 出來就能用了,還要配置各種屬性,所以我們一般不會自己一個一個去配置這些過濾器。

二 SecurityConfigurer

為了簡化 Spring Security 中各個組件的配置,官方推出了 SecurityConfigurer,SecurityConfigurer 在 Spring Security 中扮演著非常重要的角色,其主要作用可以歸納為以下幾點:

  • 配置過濾器:在 Spring Security 中,過濾器鏈中的每一個過濾器都是通過 xxxConfigurer 來進行配置的,而這些 xxxConfigurer 實際上都是 SecurityConfigurer 的實現(xiàn)。這意味著 SecurityConfigurer 負責配置和管理安全過濾器鏈中的各個組件。
  • 初始化和配置安全構(gòu)建器:SecurityConfigurer 接口中定義了兩個主要方法:init 和 configure。init 方法用于初始化安全構(gòu)建器(SecurityBuilder),而 configure 方法則用于配置這個構(gòu)建器。這兩個方法共同確保了安全組件的正確設置和初始化。
  • 提供擴展點:SecurityConfigurer 的三個主要實現(xiàn)類(SecurityConfigurerAdapter、GlobalAuthenticationConfigurerAdapter、WebSecurityConfigurer)為開發(fā)者提供了擴展 Spring Security 功能的點。特別是,大部分的 xxxConfigurer 都是 SecurityConfigurerAdapter 的子類,這使得開發(fā)者能夠輕松地定制和擴展安全配置。
  • 構(gòu)建安全上下文:通過配置和組合不同的 SecurityConfigurer 實現(xiàn),可以構(gòu)建一個完整的安全上下文,包括身份驗證、授權(quán)、加密等各個方面,從而確保應用程序的安全性。

換句話說,Spring Security 中的各種 Filter,其實都有各自對應的 xxxConfigurer,通過這些 xxxConfigurer 完成了對 Filter 的配置。

舉幾個簡答的例子,如:

  • CorsConfigurer 負責配置 CorsFilter
  • RememberMeConfigurer 負責配置 RememberMeAuthenticationFilter
  • FormLoginConfigurer 負責配置 UsernamePasswordAuthenticationFilter

以上是前置知識。

三 SecurityBuilder

SecurityBuilder 是 Spring Security 框架中的一個核心接口,它體現(xiàn)了建造者設計模式,用于構(gòu)建和配置安全組件。這個接口并不直接與安全功能如認證或授權(quán)的具體實現(xiàn)綁定,而是提供了一種靈活的方式來組織和裝配這些功能組件,特別是在構(gòu)建安全上下文和過濾器鏈過程中。

核心特點

  • 靈活性與模塊化:通過 SecurityBuilder,開發(fā)者可以以模塊化的方式添加、移除或替換安全配置中的各個部分,而不需要了解整個安全架構(gòu)的細節(jié)。這促進了代碼的復用性和可維護性。
  • 層次結(jié)構(gòu):在 Spring Security 中,SecurityBuilder及其子類形成了一個層次結(jié)構(gòu),允許配置像嵌套娃娃一樣層層深入,每一個層級都可以貢獻自己的配置邏輯,最終形成一個完整的安全配置。
  • 安全上下文構(gòu)建:在認證過程中,SecurityBuilder 用于構(gòu)造 SecurityContext,該上下文中包含了當前認證主體(通常是用戶)的詳細信息,以及主體所關聯(lián)的權(quán)限和角色。
  • 過濾器鏈構(gòu)建:在 Web 應用中,SecurityBuilder 還用于構(gòu)建 FilterChainProxy,這是一個關鍵組件,負責組織和執(zhí)行一系列的過濾器,這些過濾器負責處理 HTTP 請求的安全性,比如檢查用戶是否已經(jīng)登錄、是否有權(quán)限訪問某個資源等。

簡而言之,在 SecurityBuilder 的子類 AbstractConfiguredSecurityBuilder 中,有一個名為 configurers 的集合,這個集合中保存的就是我們前面所說的各種 xxxConfigure 對象。

AbstractConfiguredSecurityBuilder 收集到所有的 xxxConfigure 之后,將來會調(diào)用每個 xxxConfigure 的 configure 方法完成過濾器的構(gòu)建。

另外很重要的一點,HttpSecurity 也是一個 SecurityBuilder。因此,HttpSecurity 其實就是幫我們收集各種各樣的 xxxConfigure,并存入到 configurers 集合中,以備將來構(gòu)建過濾器使用。

四 HttpSecurity

根據(jù)前面的介紹,我們知道,無論我們怎么配置,最終拿到手的一定是一個 DefaultSecurityFilterChain 對象,因為這是 SecurityFilterChain 的唯一實現(xiàn)類。

所以,HttpSecurity 其實就是在幫我們配置 DefaultSecurityFilterChain,我們看到 HttpSecurity 里邊就有兩個非常關鍵的屬性:

private List<OrderedFilter> filters = new ArrayList<>();
private RequestMatcher requestMatcher = AnyRequestMatcher.INSTANCE;

這兩個恰恰就是構(gòu)建 DefaultSecurityFilterChain 所需的關鍵參數(shù)。

事實確實如此,我們看到,在 HttpSecurity#performBuild 方法中,就是利用這兩個參數(shù)構(gòu)建出來了 DefaultSecurityFilterChain:

@Override
protected DefaultSecurityFilterChain performBuild() {
	ExpressionUrlAuthorizationConfigurer<?> expressionConfigurer = getConfigurer(
			ExpressionUrlAuthorizationConfigurer.class);
	AuthorizeHttpRequestsConfigurer<?> httpConfigurer = getConfigurer(AuthorizeHttpRequestsConfigurer.class);
	boolean oneConfigurerPresent = expressionConfigurer == null ^ httpConfigurer == null;
	this.filters.sort(OrderComparator.INSTANCE);
	List<Filter> sortedFilters = new ArrayList<>(this.filters.size());
	for (Filter filter : this.filters) {
		sortedFilters.add(((OrderedFilter) filter).filter);
	}
	return new DefaultSecurityFilterChain(this.requestMatcher, sortedFilters);
}

這里先對 filters 進行排序,然后據(jù)此創(chuàng)建出來 DefaultSecurityFilterChain 對象。

那么問題來了,filters 中的過濾器從何而來呢?

前面我們提到,HttpSecurity 本質(zhì)上也是一個 SecurityBuilder,我們平時在 HttpSecurity 配置的各種東西,本質(zhì)上其實就是一個 xxxConfigure,這些 xxxConfigure 被 HttpSecurity 收集起來,最后會遍歷收集起來的 xxxConfigure,調(diào)用其 configure 方法,最終獲取過濾器,并將獲取到的過濾器存入到 filters 集合中。

這里松哥以我們最為常見的登錄配置為例來和大家捋一捋這個流程。

新版的登錄配置我們一般按照如下方式來配置:

http.formLogin(f -> f.permitAll());

這個方法如下:

public HttpSecurity formLogin(Customizer<FormLoginConfigurer<HttpSecurity>> formLoginCustomizer) throws Exception {
	formLoginCustomizer.customize(getOrApply(new FormLoginConfigurer<>()));
	return HttpSecurity.this;
}

從這段源碼可以看到,我們配置里邊寫的 lambda,其實就是在配置 FormLoginConfigurer 對象。

getOrApply 方法主要主要有兩方面的作用:

  • 確保這個 Bean 不會重復配置。
  • 如果該 Bean 是第一次配置,那么將該對象添加到 SecurityBuilder 中(其實就是 HttpSecurity 對象自身),這個 SecurityBuilder 里邊保存了所有配置好的 xxxConfigure 對象,將來在過濾器鏈構(gòu)建的時候,會去遍歷這些 xxxConfigure 對象并調(diào)用其 configure 方法,完成過濾器的構(gòu)建。

在 FormLoginConfigurer#init 方法中,完成了和登錄相關過濾器的配置,如:

  • 登錄請求處理過濾器(構(gòu)造方法中完成的)
  • 注銷過濾器的配置
  • 登錄失敗端點配置
  • 登錄頁面的配置

這里涉及到的屬性都會在對應的 xxxConfigurer 中完成配置。

當過濾器鏈開始構(gòu)建的時候,會調(diào)用到所有 xxxConfigurer 的 configure 方法,在這個方法中,最終完成相關過濾器的創(chuàng)建,并將之添加到 HttpSecurity 的 filters 屬性這個集合中。

FormLoginConfigurer 的 configure 方法在其父類中,如下:

@Override
public void configure(B http) throws Exception {
	PortMapper portMapper = http.getSharedObject(PortMapper.class);
	if (portMapper != null) {
		this.authenticationEntryPoint.setPortMapper(portMapper);
	}
	RequestCache requestCache = http.getSharedObject(RequestCache.class);
	if (requestCache != null) {
		this.defaultSuccessHandler.setRequestCache(requestCache);
	}
	this.authFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
	this.authFilter.setAuthenticationSuccessHandler(this.successHandler);
	this.authFilter.setAuthenticationFailureHandler(this.failureHandler);
	if (this.authenticationDetailsSource != null) {
		this.authFilter.setAuthenticationDetailsSource(this.authenticationDetailsSource);
	}
	SessionAuthenticationStrategy sessionAuthenticationStrategy = http
		.getSharedObject(SessionAuthenticationStrategy.class);
	if (sessionAuthenticationStrategy != null) {
		this.authFilter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy);
	}
	RememberMeServices rememberMeServices = http.getSharedObject(RememberMeServices.class);
	if (rememberMeServices != null) {
		this.authFilter.setRememberMeServices(rememberMeServices);
	}
	SecurityContextConfigurer securityContextConfigurer = http.getConfigurer(SecurityContextConfigurer.class);
	if (securityContextConfigurer != null && securityContextConfigurer.isRequireExplicitSave()) {
		SecurityContextRepository securityContextRepository = securityContextConfigurer
			.getSecurityContextRepository();
		this.authFilter.setSecurityContextRepository(securityContextRepository);
	}
	this.authFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
	F filter = postProcess(this.authFilter);
	http.addFilter(filter);
}

關鍵在最后這一句 http.addFilter(filter);,這句代碼將配置好的過濾器放到了 HttpSecurity 的 filters 集合中。

其他的也都類似,例如配置 CorsFilter 的 CorsConfigurer#configure 方法,如下:

@Override
public void configure(H http) {
	ApplicationContext context = http.getSharedObject(ApplicationContext.class);
	CorsFilter corsFilter = getCorsFilter(context);
	http.addFilter(corsFilter);
}

這些被添加到 HttpSecurity 的 filters 屬性上的 Filter,最終就成為了創(chuàng)建 DefaultSecurityFilterChain 的原材料。

類似的道理,我們也可以分析出 disable 方法的原理,例如我們要關閉 csrf,一般配置如下:

.csrf(c -> c.disable());

那么很明顯,這段代碼其實就是調(diào)用了 CsrfConfigurer 的 disable 方法:

public B disable() {
	getBuilder().removeConfigurer(getClass());
	return getBuilder();
}

該方法直接從 SecurityBuilder 的 configurers 集合中移除了 CsrfConfigurer,所以導致最終調(diào)用各個 xxxConfigure 的 configure 方法的時候,沒有 CsrfConfigurer#configure 了,就導致 csrf 過濾器沒有配置上,進而 CSRF filter 失效。

以上就是詳解HttpSecurity是如何組裝過濾器鏈的的詳細內(nèi)容,更多關于HttpSecurity組裝過濾器鏈的資料請關注腳本之家其它相關文章!

相關文章

  • MyBatis 與 Spring 的完美整合方法

    MyBatis 與 Spring 的完美整合方法

    MyBatis 和 Spring 兩大框架已經(jīng)成了 Java 互聯(lián)網(wǎng)技術主流框架組合,它們經(jīng)受住了大數(shù)據(jù)量和大批量請求的考驗,在互聯(lián)網(wǎng)系統(tǒng)中得到了廣泛的應用。這篇文章主要介紹了MyBatis 與 Spring 整合,需要的朋友可以參考下
    2018-04-04
  • MyBatisPlus3.4.3版自動生成代碼的使用過程

    MyBatisPlus3.4.3版自動生成代碼的使用過程

    這篇文章主要介紹了MyBatisPlus3.4.3版自動生成代碼的使用,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-04-04
  • 利用Jackson實現(xiàn)數(shù)據(jù)脫敏的示例詳解

    利用Jackson實現(xiàn)數(shù)據(jù)脫敏的示例詳解

    在我們的企業(yè)項目中,為了保護用戶隱私,數(shù)據(jù)脫敏成了必不可少的操作,那么我們怎么優(yōu)雅的利用Jackson實現(xiàn)數(shù)據(jù)脫敏呢,本文就來和大家詳細聊聊,希望對大家有所幫助
    2023-05-05
  • 解決IDEA使用springBoot創(chuàng)建項目,lombok標注實體類后編譯無報錯,但是運行時報錯問題

    解決IDEA使用springBoot創(chuàng)建項目,lombok標注實體類后編譯無報錯,但是運行時報錯問題

    文章詳細描述了在使用lombok的@Data注解標注實體類時遇到編譯無誤但運行時報錯的問題,分析了可能的原因,并提供了解決步驟
    2025-01-01
  • SpringBoot Admin 如何實現(xiàn)Actuator端點可視化監(jiān)控

    SpringBoot Admin 如何實現(xiàn)Actuator端點可視化監(jiān)控

    這篇文章主要介紹了SpringBoot Admin 如何實現(xiàn)Actuator端點可視化監(jiān)控,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Java踩坑記錄之Arrays.AsList

    Java踩坑記錄之Arrays.AsList

    這篇文章主要給大家介紹了關于Java踩坑記錄之Arrays.AsList的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-11-11
  • Spring Mvc中傳遞參數(shù)方法之url/requestMapping詳解

    Spring Mvc中傳遞參數(shù)方法之url/requestMapping詳解

    在開發(fā)中,參數(shù)傳遞是必不可少的一個功能,下面這篇文章主要給大家介紹了關于Spring Mvc中傳遞參數(shù)方法之url/requestMapping的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-07-07
  • 從 Spring Boot 3+Java 21 到 Spring Boot 4+Java 25遷移全指南與注意事項

    從 Spring Boot 3+Java 21 到 Spri

    本文介紹了從SpringBoot3+Java21升級到SpringBoot4+Java25的具體步驟與注意事項,主要包含環(huán)境與依賴自查、代碼適配、進階優(yōu)化、測試與驗證以及遷移checklist等內(nèi)容,感興趣的朋友跟隨小編一起看看吧
    2026-04-04
  • 在mybatis中去除多余的前綴或者后綴操作

    在mybatis中去除多余的前綴或者后綴操作

    這篇文章主要介紹了在mybatis中去除多余的前綴或者后綴操作。具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11
  • 數(shù)組在java中的擴容的實例方法

    數(shù)組在java中的擴容的實例方法

    在本篇文章里小編給大家分享的是一篇關于數(shù)組在java中的擴容的實例方法內(nèi)容,有興趣的朋友們可以學習下。
    2021-01-01

最新評論

陵川县| 浠水县| 甘泉县| 瑞昌市| 德清县| 姜堰市| 奉化市| 高平市| 顺义区| 安塞县| 来宾市| 霍山县| 巩义市| 吉木乃县| 辽宁省| 霍林郭勒市| 西峡县| 桑植县| 陵川县| 涿鹿县| 仙桃市| 通道| 巩义市| 宜昌市| 英吉沙县| 隆回县| 田林县| 平罗县| 侯马市| 当涂县| 湖北省| 福州市| SHOW| 肃宁县| 铜梁县| 巫山县| 永安市| 隆林| 葫芦岛市| 九江市| 宁强县|