Spring Security 竟然可以同時存在多個過濾器鏈?

      網友投稿 822 2022-05-30

      這是來自一個小伙伴的提問,我覺得很有必要和大家聊一聊這個問題:

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

      這就涉及到 Spring Security 中過濾器鏈的配置問題了,本文松哥就來和大家稍微聊一聊。

      本文是 Spring Security 系列第 36 篇,閱讀前面文章有助于更好的理解本文:

      挖一個大坑,Spring Security 開搞!

      松哥手把手帶你入門 Spring Security,別再問密碼怎么解密了

      手把手教你定制 Spring Security 中的表單登錄

      Spring Security 做前后端分離,咱就別做頁面跳轉了!統(tǒng)統(tǒng) JSON 交互

      Spring Security 中的授權操作原來這么簡單

      Spring Security 如何將用戶數據存入數據庫?

      Spring Security+Spring Data Jpa 強強聯(lián)手,安全管理只有更簡單!

      Spring Boot + Spring Security 實現(xiàn)自動登錄功能

      Spring Boot 自動登錄,安全風險要怎么控制?

      在微服務項目中,Spring Security 比 Shiro 強在哪?

      SpringSecurity 自定義認證邏輯的兩種方式(高級玩法)

      Spring Security 中如何快速查看登錄用戶 IP 地址等信息?

      Spring Security 自動踢掉前一個登錄用戶,一個配置搞定!

      Spring Boot + Vue 前后端分離項目,如何踢掉已登錄用戶?

      Spring Security 自帶防火墻!你都不知道自己的系統(tǒng)有多安全!

      什么是會話固定攻擊?Spring Boot 中要如何防御會話固定攻擊?

      集群化部署,Spring Security 要如何處理 session 共享?

      松哥手把手教你在 SpringBoot 中防御 CSRF 攻擊!so easy!

      要學就學透徹!Spring Security 中 CSRF 防御源碼解析

      Spring Boot 中密碼加密的兩種姿勢!

      Spring Security 要怎么學?為什么一定要成體系的學習?

      Spring Security 兩種資源放行策略,千萬別用錯了!

      松哥手把手教你入門 Spring Boot + CAS 單點登錄

      Spring Boot 實現(xiàn)單點登錄的第三種方案!

      Spring Boot+CAS 單點登錄,如何對接數據庫?

      Spring Boot+CAS 默認登錄頁面太丑了,怎么辦?

      用 Swagger 測試接口,怎么在請求頭中攜帶 Token?

      Spring Boot 中三種跨域場景總結

      Spring Boot 中如何實現(xiàn) HTTP 認證?

      Spring Security 中的四種權限控制方式

      Spring Security 多種加密方案共存,老破舊系統(tǒng)整合利器!

      神奇!自己 new 出來的對象一樣也可以被 Spring 容器管理!

      Spring Security 配置中的 and 到底該怎么理解?

      一文搞定 Spring Security 異常處理機制!

      寫了這么多年代碼,這樣的登錄方式還是頭一回見!

      1.從過濾器開始

      即使大家沒有仔細研究過 Spring Security 中認證、授權功能的實現(xiàn)機制,大概也都多多少少聽說過 Spring Security 這些功能是通過過濾器來實現(xiàn)的。

      Spring Security 竟然可以同時存在多個過濾器鏈?

      是的,沒錯!Spring Security 中一共提供了 32 個過濾器,其中默認使用的有 15 個,這些過濾器松哥在以后的文章中再和大家細說,今天我們就先來看看過濾器的配置問題。

      在一個 Web 項目中,請求流程大概如下圖所示:

      請求從客戶端發(fā)起(例如瀏覽器),然后穿過層層 Filter,最終來到 Servlet 上,被 Servlet 所處理。

      那有小伙伴要問了,Spring Security 中默認的 15 個過濾器就是這樣嵌套在 Client 和 Servlet 之間嗎?

      不是的!

      上圖中的 Filter 我們可以稱之為 Web Filter,Spring Security 中的 Filter 我們可以稱之為 Security Filter,它們之間的關系如下圖:

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

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

      2.多個過濾器鏈

      上面和大家介紹的是單個過濾器鏈,實際上,在 Spring Security 中,可能存在多個過濾器鏈。

      在松哥前面講 OAuth2 系列的時候,有涉及到多個過濾器鏈,但是一直沒有拎出來單獨講過,今天就來和大家分享一下。

      有人會問,下面這種配置是不是就是多個過濾器鏈?

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

      1

      2

      3

      4

      5

      6

      7

      8

      9

      這樣的配置相信大家都見過,但是這并不是多個過濾器鏈,這是一個過濾器鏈。因為不管是 /admin/** 還是 /user/** ,走過的過濾器都是一樣的,只是不同的路徑判斷條件不一樣而已。

      如果系統(tǒng)存在多個過濾器鏈,多個過濾器鏈會在 FilterChainProxy 中進行劃分,如下圖:

      可以看到,當請求到達 FilterChainProxy 之后,F(xiàn)ilterChainProxy 會根據請求的路徑,將請求轉發(fā)到不同的 Spring Security Filters 上面去,不同的 Spring Security Filters 對應了不同的過濾器,也就是不同的請求將經過不同的過濾器。

      正常情況下,我們配置的都是一個過濾器鏈,多個過濾器鏈怎么配置呢?松哥給大家一個舉一個簡單的例子:

      @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("江南一點雨").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

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      首先,SecurityConfig 不再需要繼承自 WebSecurityConfigurerAdapter 了,只是作為一個普通的配置類,加上 @Configuration 注解即可。

      提供 UserDetailsService 實例,相當于是我們的數據源。

      創(chuàng)建靜態(tài)內部類繼承 WebSecurityConfigurerAdapter 類,同時用 @Configuration 注解標記靜態(tài)內部類是一個配置類,配置類里邊的代碼就和之前的一樣了,無需贅述。

      每一個靜態(tài)內部類相當于就是一個過濾器鏈的配置。

      注意在靜態(tài)內部類里邊,我沒有使用 http.authorizeRequests() 開始,http.authorizeRequests() 配置表示該過濾器鏈過濾的路徑是 /**。在靜態(tài)內部類里邊,我是用了 http.antMatcher("/bar/**") 開啟配置,表示將當前過濾器鏈的攔截范圍限定在 /bar/**。

      當存在多個過濾器鏈的時候,必然會有一個優(yōu)先級的問題,所以每一個過濾器鏈的配置類上通過 @Order(2) 注解來標記優(yōu)先級。

      從上面這段代碼中大家可以看到,configure(HttpSecurity http) 方法似乎就是在配置過濾器鏈?是的沒錯!我們在該方法中的配置,都是在添加/移除/修改 Spring Security 默認提供的過濾器,所以該方法就是在配置 Spring Security 中的過濾器鏈,至于是怎么配置的,松哥以后抽時間再來和大家細說。

      3.回到問題

      最后,我們在回到一開始小伙伴提的問題。

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

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

      4.小結

      好啦,今天就和小伙伴們簡單分享一下 Spring Security 中過濾器鏈的問題,后面松哥再抽時間和大家聊一聊過濾器鏈中每一個過濾器的配置以及含義~公眾號【江南一點雨】后臺回復 springsecurity,獲取Spring Security系列 40+ 篇完整文章~

      如果小伙伴們覺得有收獲,記得點個在看鼓勵下松哥哦~

      Spring Spring Boot

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:電機控制進階3——PID串級控制
      下一篇:四大核心價值!華為AIOps服務讓運維不再成為電信業(yè)痛點
      相關文章
      亚洲成在人线aⅴ免费毛片| 国产亚洲精AA在线观看SEE| 亚洲成a人无码av波多野按摩 | 精品亚洲AV无码一区二区| 亚洲αv久久久噜噜噜噜噜| 亚洲色欲久久久综合网东京热| 狠狠色婷婷狠狠狠亚洲综合| 亚洲日本一区二区一本一道| 亚洲国产成人久久一区久久| 亚洲国模精品一区| 亚洲精品黄色视频在线观看免费资源 | 亚洲熟妇中文字幕五十中出| 亚洲宅男天堂在线观看无病毒| 国产偷国产偷亚洲高清日韩 | 国产亚洲国产bv网站在线| 亚洲乱码日产精品BD在线观看| 亚洲日韩在线视频| 亚洲女人影院想要爱| 亚洲制服丝袜一区二区三区| 激情亚洲一区国产精品| 亚洲娇小性xxxx| 亚洲第一成年免费网站| 99亚洲男女激情在线观看| 亚洲av高清在线观看一区二区| 亚洲av无码成人精品区在线播放| 亚洲国产精品日韩专区AV| 亚洲精品成人区在线观看| 一本色道久久综合亚洲精品高清| 亚洲综合另类小说色区| 亚洲AV综合色一区二区三区| 亚洲精品人成在线观看| 亚洲国产超清无码专区| jiz zz在亚洲| 精品亚洲成A人在线观看青青| 亚洲国产免费综合| 久久精品国产亚洲网站| 77777_亚洲午夜久久多人| 亚洲av无码国产综合专区| 亚洲国产精品无码久久九九大片 | 亚洲AV成人精品日韩一区18p| 国内精品久久久久久久亚洲|