这是我参与11月更文挑战的第23天,活动详情查看:2021最后一次更文挑战
写在前面
目前Spring Security 专题现在已经更新到17篇了。算上本篇文章已经有18篇了,感兴趣的小伙伴可以点击我头像查看专栏。我们一起学习,
多说一句,目前正在进行的是并发队列专栏和Security专栏,设计模式专栏已完结,感兴趣的伙伴可以去看下
今天我们来聊聊 Security当中的过滤器,看过我以前文章的朋友应该知道 Security的权限功能是通过过滤器来实现的。而且这个过滤器还不止一个,默认使用的是15个。而且全部好像有32个。具体等我研究完这些过滤器了 再给大家一一分享
过滤器
我们从过滤器开始。先来回顾下在一个 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 之中。
多个过滤器链
上面和大家介绍的是单个过滤器链,实际上,在 Spring Security 中,可能存在多个过滤器链。
看下面这段代码配置是不是就是多个过滤器链?
@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("shushi").password("{bcrypt}$2a$10$Sb1gAUH4wwazfNiqflKZve4Ubh.spJcxgHG8Cp29DeGya5zsHENqi").roles("admin", "aaa", "bbb").build());
manager.createUser(User.withUsername("yn").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) 注解来标记优先级。
OK 关于Spring Security 的多个过滤器学习就到这里。我们下期再见 加油!
弦外之音
感谢你的阅读,如果你感觉学到了东西,您可以点赞,关注。也欢迎有问题我们下面评论交流
加油! 我们下期再见!
给大家分享几个我前面写的几篇骚操作
近期评论