WebSecurityConfigurer 是 springsecurity 框架配置的类
ResourceServerConfigurerAdapter 是 oauth2 框架配置的类
1、Spring Security的配置
Java在正常servelet处理http的请求可能会经过很多的filter,大体例子像下面这个:
而spring security又是怎么处理的呢,详见下图:
从图中可以看出spring security自己有一个叫 FilterChainProxy 代理类,该类也实现了 servlet 接口。FilterChainProxy 内部有一个 List filterChains,而 SecurityFilterChain 是一个接口也是一个 chain,每个chain里有若干个 filter,既然有多个filter chain,那么来了一个http请求,这个请求(通过该请求的url来判断)应该由哪个或者哪些 filter chain 来进行处理呢?
在spring security里一个请求只会被一个filter chain进行处理,也就是 spring security 通过遍历 Filter Chains这个集合时,只要找到能处理该请求的 filter chain 就不再进行其他的 filter chain 匹配。
如下图:
比如来了一个请求,url是:/foo/**,那么他会被会第一个filter chain处理,后面的两个filter chain会被忽略掉。`
当我们在 spring boot 引入了spring-security 的相关包时,security默认会为我们创建一个默认 WebSecurityConfigurerAdapter,他拦截所有的http请求 (/**),且这个Order的值是:@Order(100) ,order值越小过滤链越在前。Security默认还会为我们创建一些filter:
每个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/**")
...;
}
}
2、ResourceServerConfigurer的配置
如果同时在处理同一个Url(如:/api/**)应该是哪个生效?
WebSecurityConfigurerAdapter与ResourceServerConfigurerAdapter同时在的话且都配置了处理url为:/api/**,默认是后者会生效。我们在写ResourceServerConfigurerAdapter时,基本上会这么写:
为什么是后者生效呢,因为默认的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,例如:
如果我们通过下面这种方式配置的话,requestMatcher值为显示No fields to display:
如果通过这种方式配置的话,requestMatcher值为显示match到的url :/aa/**
3、之间的关系
他们所属的功能模块不同,前者spring security的,后者是spring security oauth2里的。他们都是Adapter,他们都会产生一个filter Chain,他们两者可以相互配合来对不同的Url进行权限控制。
但是,我们经常在写代码的时候经常会出现这种情况,当我们在做oauth2的时候,当把两个类同时放在项目的时候,都声明了对http url的不同处理,但是就是ResourceServerConfigurerAdapter会把的http配置信息完全被覆盖掉,最后形成了,所有的请求只会在 ResourceServerConfigurerAdapter 的 fitler chain中处理,导致用户不知道这两者到底是怎么回事。
这其实是因为对spring security的配置不熟悉导致的,也就是antMatcher() 和 authorizeRequests().antMatchers()。
4、例子
只会拦截匹配到/user/**的请求,其他请求会被其他拦截器拦截
拦截所有请求,/api/* 需要有权限,其他地址都放行
上面这个例子,本意是想/api/ 端点须要被认证且要有USER权限;/user/**的端点须要被认证,
但是最终的结果是WebSecurityConfigurerAdapter相关的配置信息没生效。
因为ResourceServerConfigurer的优先级高,请求被它的过滤链所拦截
导致/user/**的接口会被放行
但是如果这么配置:
/api/**会被ResourceServerConfigurer拦截
/user/**会被WebSecurityConfigurer拦截
这样才是对的
5、antMatcher与authorizeRequests
antMatcher()是HttpSecurity的一个方法,他只告诉了Spring我只配置了一个我这个Adapter能处理哪个的url,它与authorizeRequests()没有任何关系。
然后使用 authorizeRequests().antMatchers() 是告诉你在 antMatchers()中指定的一个或多个路径,比如执行permitAll()或hasRole()。他们在第一个http.antMatcher()匹配时就会生效。
所以,WebSecurityConfigurerAdapter 与 ResourceServerConfigurerAdapter 同时使用,其实和spring security的多个HttpSecurity配置是一样的,原理也差不多是一样的。