spring security的內部filter

咱們在用spring boot 配合spring security和oauth2的時候常常會把這兩個類都用上,網上不少教程都沒有告訴咱們他們之間的關係是什麼?若是同時在處理同一個Url(如:/api/**)應該是哪一個生效?spring security的內部filter是個什麼樣子?帶着這些疑問咱們一層層的來扒開。spring

spring security的內部filter是個什麼樣子?

Java在正常servelet處理http的請求可能會通過不少的filter,大致例子像下面這個:api

圖片.pngide

而spring security又是怎麼處理的呢,詳見下圖:post

圖片.png測試

從圖中能夠看出spring security本身有一個叫FilterChainProxy代理類,該類也實現了servlet接口。FilterChainProxy``內部有一個List<SecurityFilterChain> filterChains,而SecurityFilterChain是一個接口也是一個chain,每一個chain裏有若干個filter.既然有多個filter chain,那麼來了一個http請求,這個請求(經過該請求的url來判斷)應該由哪一個或者哪些filter chain來進行處理呢?在spring security裏一個請只會被一個filter chain進行處理,也就是spring security經過遍歷filterChains這個集合時,只要找到能處理該請求的filter chain就再也不進行其餘的filter chain匹配。以下圖:`url

圖片.pngspa

好比來了一個請求,url是:/foo/**,那麼他會被會第一個filter chain處理,後面的兩個filter chain會被忽略掉。`代理

當咱們在spring boot引入了spring-security的相關包時,security默認會爲咱們建立一個默認WebSecurityConfigurerAdapter,他攔截全部的http請求(/**),且這個Order的值是:SecurityProperties.BASIC_AUTH_ORDER。Security默認還會爲咱們建立一些filter:code

 

圖片.png教程

每一個filter的做用能夠在spring security中文檔中找到。

固然你能夠經過配置文件設置security.basic.enabled=false 來讓默認的失效,或者你能夠自定義一個並添加@Order值更低的WebSecurityConfigurerAdapter (or WebSecurityConfigurer) 的`@Bean``,好比像下面的代碼:

@Order(SecurityProperties.BASIC_AUTH_ORDER - 10)

public class ApplicationConfigurerAdapter extends WebSecurityConfigurerAdapter {

 @Override

 protected void configure(HttpSecurity http) throws Exception {

 http.antMatcher("/foo/**")

 ...;

 }

}

若是同時在處理同一個Url(如:/api/**)應該是哪一個生效?

WebSecurityConfigurerAdapter與ResourceServerConfigurerAdapter同時在的話且都配置了處理url爲:/api/**,默認是後者會生效。咱們在寫ResourceServerConfigurerAdapter時,基本上會這麼寫:

圖片.png

爲何是後者生效呢,由於默認的WebSecurityConfigurerAdapter裏的@Order值是100(咱們能夠在該類上能夠明確看到@Order(100)),而咱們在ResourceServerConfigurerAdapter上添加了@EnableResourceServer註解,這個玩意兒是幹什麼用的呢?他其中之一就是定義了@Order值爲3(該註解裏引用了ResourceServerConfiguration,這個類裏面定義了Order值).在spring 的體系裏Order值越小優先級越高,因此ResourceServerConfigurerAdapter優先級比另一個更高,他會優先處理,而WebSecurityConfigurerAdapter會失效。

若是咱們想讓WebSecurityConfigurerAdapter比ResourceServerConfigurerAdapter優先級高的話,只需要讓前者的@Order值比後者的@Order值更低就好了。

注意:咱們每聲明一個*Adapter類,都會產生一個filterChain。前面咱們講到一個request(匹配url)只能被一個filterChain處理,這就解釋了爲何兩者Adapter同時在的時候,前者默認爲何會失效的緣由。咱們能夠在FilterChainProxy中的getFilters(HttpServletRequest request)方法中能夠看到有哪些filter chain,並處理哪些url,例如:

圖片.png

 

a.若是咱們經過這種方式配置的話,requestMatcher值爲顯示No fields to display:

 

圖片.png

b.若是經過這種方式配置的話,requestMatcher值爲顯示match到的url :/aa/**

圖片.png

具體爲何,見下文。

他們之間的關係是什麼?

他們所屬的功能模塊不一樣,前者spring security的,後者是spring security oauth2裏的。他們都是Adapter,他們都會產生一個filter Chain,他們二者能夠相互配合來對不一樣的Url進行權限控制。

可是,咱們常常在寫代碼的時候常常會出現這種狀況,當咱們在作oauth2的時候,當把兩個類同時放在項目的時候,都聲明瞭對http url的不一樣處理,可是就是ResourceServerConfigurerAdapter會把的http配置信息徹底被覆蓋掉,最後造成了,全部的請求只會在ResourceServerConfigurerAdapter的fitler chain中處理,致使用戶不知道這二者究竟是怎麼回事。

這實際上是由於對spring security的配置不熟悉致使的,也就是antMatcher()``和authorizeRequests().antMatchers()。

讓咱們看兩個例子:

例1:

圖片.png

 

圖片.png

上面這個例子,本意是想/api/* 端點需要被認證且要有USER權限;/user/**的端點需要被認證,可是最終的結果是WebSecurityConfigurerAdapter相關的配置信息沒生效。

咱們使用postman來測試一下:

 

圖片.png

圖片.png

從這結果咱們能夠看出來:/user/* 的端點沒有被保護起來,/api/*的端點實際是被ResourceServerConfigurerAdapter產生的filter chain進行處理的。

這和咱們想要的效果不同呢,該怎麼辦呢,咱們來看看例子2:

例2:

 

圖片.png

 

圖片.png

postman測試:

圖片.png

 

圖片.png

能夠看出來/api/的端點實際是被ResourceServerConfigurerAdapter產生的filter chain進行處理的。而/user/ 的端點也被保護起來,可是此次被處理的是由WebSecurityConfigurerAdapter產生的filter chain進行處理的。

讓咱們來看stackoverflow上的解釋:

圖片.png

大致意思就是antMatcher()``是HttpSecurity的一個方法,他只告訴了Spring我只配置了一個我這個Adapter能處理哪一個的url,它與authorizeRequests()沒有任何關係。

而後使用authorizeRequests().antMatchers()是告訴你在antMatchers()中指定的一個或多個路徑,好比執行permitAll()或hasRole()。他們在第一個http.antMatcher()匹配時就會生效。

因此,WebSecurityConfigurerAdapter與ResourceServerConfigurerAdapter同時使用,其實和spring security的多個HttpSecurity配置是同樣的,原理也差很少是同樣的。

用官方的例子:

圖片.png

一、按照正常的方式配置驗證

二、建立一個包含 @Order的 WebSecurityConfigurerAdapter實例來指定哪個 WebSecurityConfigurerAdapter應該被首先考慮。

三、 http.antMatcher代表這個 HttpSecurity 只適用於以 /api/開頭的URL。

四、建立另外一個 WebSecurityConfigurerAdapter實例。若是URL沒有以 /api/開頭,這個配置將會被使用。這個配置在 ApiWebSecurityConfigurationAdapter 以後生效,由於其含有一個 @Order值爲1.沒有 @Order默認是最後一個生效。

相關文章
相關標籤/搜索