如何分析Spring Security中过滤器链的配置问题,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。
创新互联专注于企业营销型网站、网站重做改版、武城网站定制设计、自适应品牌网站建设、H5开发、电子商务商城网站建设、集团公司官网建设、成都外贸网站建设、高端网站制作、响应式网页设计等建站业务,价格优惠性价比高,为武城等各大城市提供网站开发制作服务。
首先这个问题本身是有点问题的,因为 http.authorizeRequests()
并非总是第一个,虽然大部分情况下,我们看到的是第一个,但是也有很多情况 http.authorizeRequests()
不是首先出现。要搞明白这个问题,我们就要搞清楚 http.authorizeRequests()
到底是啥意思!
这就涉及到 Spring Security 中过滤器链的配置问题
1.从过滤器开始
即使大家没有仔细研究过 Spring Security 中认证、授权功能的实现机制,大概也都多多少少听说过 Spring Security 这些功能是通过过滤器来实现的。
是的,没错!Spring Security 中一共提供了 32 个过滤器,其中默认使用的有 15 个,这些过滤器松哥在以后的文章中再和大家细说,今天我们就先来看看过滤器的配置问题。
在一个 Web 项目中,请求流程大概如下图所示:
请求从客户端发起(例如浏览器),然后穿过层层 Filter,最终来到 Servlet 上,被 Servlet 所处理。
那有小伙伴要问了,Spring Security 中默认的 15 个过滤器就是这样嵌套在 Client 和 Servlet 之间吗?
不是的!
上图中的 Filter 我们可以称之为 Web Filter,Spring Security 中的 Filter 我们可以称之为 Security Filter,它们之间的关系如下图:
可以看到,Spring Security Filter 并不是直接嵌入到 Web Filter 中的,而是通过 FilterChainProxy 来统一管理 Spring Security Filter,FilterChainProxy 本身则通过 Spring 提供的 DelegatingFilterProxy 代理过滤器嵌入到 Web Filter 之中。
❝DelegatingFilterProxy 很多小伙伴应该比较熟悉,在 Spring 中手工整合 Spring Session、Shiro 等工具时都离不开它,现在用了 Spring Boot,很多事情 Spring Boot 帮我们做了,所以有时候会感觉 DelegatingFilterProxy 的存在感有所降低,实际上它一直都在。
2.多个过滤器链
上面和大家介绍的是单个过滤器链,实际上,在 Spring Security 中,可能存在多个过滤器链。
在松哥前面讲 OAuth3 系列的时候,有涉及到多个过滤器链,但是一直没有拎出来单独讲过,今天就来和大家分享一下。
有人会问,下面这种配置是不是就是多个过滤器链?
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("admin")
.antMatchers("/user/**").hasRole("user")
.anyRequest().authenticated()
...
.csrf().disable();
}
这样的配置相信大家都见过,但是这并不是多个过滤器链,这是一个过滤器链。因为不管是 /admin/**
还是 /user/**
,走过的过滤器都是一样的,只是不同的路径判断条件不一样而已。
如果系统存在多个过滤器链,多个过滤器链会在 FilterChainProxy 中进行划分,如下图:
可以看到,当请求到达 FilterChainProxy 之后,FilterChainProxy 会根据请求的路径,将请求转发到不同的 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();
}
}
}
首先,SecurityConfig 不再需要继承自 WebSecurityConfigurerAdapter 了,只是作为一个普通的配置类,加上 @Configuration 注解即可。 提供 UserDetailsService 实例,相当于是我们的数据源。 创建静态内部类继承 WebSecurityConfigurerAdapter 类,同时用 @Configuration 注解标记静态内部类是一个配置类,配置类里边的代码就和之前的一样了,无需赘述。 每一个静态内部类相当于就是一个过滤器链的配置。 注意在静态内部类里边,我没有使用 http.authorizeRequests()
开始,http.authorizeRequests()
配置表示该过滤器链过滤的路径是/**
。在静态内部类里边,我是用了http.antMatcher("/bar/**")
开启配置,表示将当前过滤器链的拦截范围限定在/bar/**
。当存在多个过滤器链的时候,必然会有一个优先级的问题,所以每一个过滤器链的配置类上通过 @Order(2) 注解来标记优先级。
从上面这段代码中大家可以看到,configure(HttpSecurity http) 方法似乎就是在配置过滤器链?是的没错!我们在该方法中的配置,都是在添加/移除/修改 Spring Security 默认提供的过滤器,所以该方法就是在配置 Spring Security 中的过滤器链,至于是怎么配置的,松哥以后抽时间再来和大家细说。
3.回到问题
最后,我们在回到一开始小伙伴提的问题。
首先,http.authorizeRequests()
配置并非总在第一行出现,如果只有一个过滤器链,他总是在第一行出现,表示该过滤器链的拦截规则是 /**
(请求只有先被过滤器链拦截下来,接下来才会进入到不同的 Security Filters 中进行处理),如果存在多个过滤器链,就不一定了。
仅仅从字面意思来理解,authorizeRequests() 方法的返回值是 ExpressionUrlAuthorizationConfigurer.antMatchers("/admin/**").hasRole("admin").antMatchers("/user/**").hasRole("user")
。
看完上述内容,你们掌握如何分析Spring Security中过滤器链的配置问题的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注创新互联行业资讯频道,感谢各位的阅读!
当前名称:如何分析SpringSecurity中过滤器链的配置问题
浏览路径:http://lswzjz.com/article/pcjiih.html