共计 5072 个字符,预计需要花费 13 分钟才能阅读完成。
这是来自一个小伙伴的发问,我觉得很有必要和大家聊一聊这个问题:
首先这个问题自身是有点问题的,因为 http.authorizeRequests()
并非总是第一个,尽管大部分状况下,咱们看到的是第一个,然而也有很多状况 http.authorizeRequests()
不是首先呈现。要搞明确这个问题,咱们就要搞清楚 http.authorizeRequests()
到底是啥意思!
这就波及到 Spring Security 中过滤器链的配置问题了,本文松哥就来和大家略微聊一聊。
本文是 Spring Security 系列第 36 篇,浏览后面文章有助于更好的了解本文:
- 挖一个大坑,Spring Security 开搞!
- 松哥手把手带你入门 Spring Security,别再问明码怎么解密了
- 手把手教你定制 Spring Security 中的表单登录
- Spring Security 做前后端拆散,咱就别做页面跳转了!通通 JSON 交互
- Spring Security 中的受权操作原来这么简略
- Spring Security 如何将用户数据存入数据库?
- Spring Security+Spring Data Jpa 强强联手,平安治理只有更简略!
- Spring Boot + Spring Security 实现主动登录性能
- Spring Boot 主动登录,平安危险要怎么管制?
- 在微服务项目中,Spring Security 比 Shiro 强在哪?
- SpringSecurity 自定义认证逻辑的两种形式 (高级玩法)
- Spring Security 中如何疾速查看登录用户 IP 地址等信息?
- Spring Security 主动踢掉前一个登录用户,一个配置搞定!
- Spring Boot + Vue 前后端拆散我的项目,如何踢掉已登录用户?
- Spring Security 自带防火墙!你都不晓得本人的零碎有多平安!
- 什么是会话固定攻打?Spring Boot 中要如何进攻会话固定攻打?
- 集群化部署,Spring Security 要如何解决 session 共享?
- 松哥手把手教你在 SpringBoot 中进攻 CSRF 攻打!so easy!
- 要学就学透彻!Spring Security 中 CSRF 进攻源码解析
- Spring Boot 中明码加密的两种姿态!
- Spring Security 要怎么学?为什么肯定要成体系的学习?
- Spring Security 两种资源放行策略,千万别用错了!
- 松哥手把手教你入门 Spring Boot + CAS 单点登录
- Spring Boot 实现单点登录的第三种计划!
- Spring Boot+CAS 单点登录,如何对接数据库?
- Spring Boot+CAS 默认登录页面太丑了,怎么办?
- 用 Swagger 测试接口,怎么在申请头中携带 Token?
- Spring Boot 中三种跨域场景总结
- Spring Boot 中如何实现 HTTP 认证?
- Spring Security 中的四种权限管制形式
- Spring Security 多种加密计划共存,老破旧零碎整合利器!
- 神奇!本人 new 进去的对象一样也能够被 Spring 容器治理!
- Spring Security 配置中的 and 到底该怎么了解?
- 一文搞定 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 中,可能存在多个过滤器链。
在松哥后面讲 OAuth2 系列的时候,有波及到多个过滤器链,然而始终没有拎进去独自讲过,明天就来和大家分享一下。
有人会问,上面这种配置是不是就是多个过滤器链?
@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<HttpSecurity>.ExpressionInterceptUrlRegistry,ExpressionUrlAuthorizationConfigurer 能够为多组不同的 RequestMatcher 配置不同的权限规定,就是大家看到的 .antMatchers("/admin/**").hasRole("admin").antMatchers("/user/**").hasRole("user")
。
4. 小结
好啦,明天就和小伙伴们简略分享一下 Spring Security 中过滤器链的问题,前面松哥再抽时间和大家聊一聊过滤器链中每一个过滤器的配置以及含意~公众号【江南一点雨】后盾回复 springsecurity,获取 Spring Security 系列 40+ 篇残缺文章~
如果小伙伴们感觉有播种,记得点个在看激励下松哥哦~