WebSecurityConfigurerAdapter與ResourceServerConfigurerAdapter使用

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

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

Java在正常servelet處理http的請求可能會經過很多的filter,大體例子像下面這個:

圖片.png

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

圖片.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匹配。如下圖:`

圖片.png

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

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

 

圖片.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

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

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

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

4、創建另一個 WebSecurityConfigurerAdapter實例。如果URL沒有以 /api/開頭,這個配置將會被使用。這個配置在 ApiWebSecurityConfigurationAdapter 之後生效,因爲其含有一個 @Order值爲1.沒有 @Order默認是最後一個生效。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章