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