FilterComparator
比较器中初始化了Spring Security 自带的Filter 的顺序,即在创建时已经确定了默认Filter的顺序。并将所有过滤器保存在一个 filterToOrder
Map中。key值是Filter的类名,value是过滤器的顺序号。- 当我们调用
HttpSecurity#addFilterAt(A, B.class)
方法时(其中B一定是先于A添加,或者B本身就是默认的过滤器),他会将我们的添加的过滤器A在 FilterComparator
,并给给我们一个和B相同的序号(addFilterBefore(A, B.class) 给A的序号比B小1,addFilterAfter(A, B.class) 给A的序号比B大1)。同时,HttpSecurity#addFilter(Filter filter)
会将我们添加的过滤器添加在 filters
List集合中, 而在List集合汇总我们手动添加的拦截器在除了 WebAsyncManagerIntegrationFilter
之外的所有系统默认的拦截器之前。 - 最后Spring Security 会调用
HttpSecurity#performBuild
方法,在这里会使用 FilterComparator
比较器对 filters
进行比较排序,序号小的在前,序号大的在后,序号相等则按照原先的filters中的顺序。 - 由于在
filters
List集合中,我们自己添加的过滤器要在除了 WebAsyncManagerIntegrationFilter
之外的所有系统默认的拦截器之前。导致了当我们调用了 HttpSecurity#addFilterAt(A, B.class)
方法时,A拦截器要先于B拦截器执行。
举例(为了好理解,纯属假设):
- 假设Spring Security 里面默认拦截器 有A、B、C 三个(在强调一遍,假设有这三个),那么
FilterComparator
构造函数中就有这三个拦截器的顺序值,假设Map值为{“AcName” : 100, “BcName” : 200, “CcName” : 300}。其中AcName是A拦截器的类名,BC同理,100,200,300是他们的序号,用于确定顺序。 - 我们添加一个拦截器 F 要调用addFilterAt(F, B.class)。那么它首先会在
FilterComparator
中注册F (保存在排序Map中),排序序号和B相同,也为 200,这时候Map 就变成了{“AcName” : 100, “BcName” : 200, “CcName” : 300, “FcName” : 200}。(如果调用addFilterBefore F的序号就会减1,变成199; 如果调用addFilterAfter F的序号就会加1,变成201) - 在 完成上述步骤后,
HttpSecurity
中也会把 F拦截器添加到一个待排序的List集合L中,然后在添加其他系统默认过滤器(相当于这个List保存了所有的过滤器,但是其调用顺序未确定,还需要经过排序后才能确定)。最终List集合L就变成了{ A, F, B, C} (之前写成了F,A,B,C了,经评论区指正,已修改),注意这个是未经排序的过滤器集合,排序后才是真正的调用顺序。
4.在调用 HttpSecurity#performBuild
方法时,会将HttpSecurity
中的过滤器集合L进行排序,排序比较器就是FilterComparator
,排序规则就是谁的排序序号小谁在前,序号大的在后,序号相同的保持 L 中的顺序。然后,得出最后的过滤器顺序,也就是最终调用顺序。
(讲的略乱,我已经尽力了。。。)
以上:内容部分木有参考
如有侵扰,联系删除。 内容仅用于自我记录学习使用。如有错误,欢迎指正
文章目录1. 分析0. FilterComparator1. HttpSecurity#addFilterAt1.1 `this.comparator.registerAt(filter.getClass(), atFilter);`1.2 `HttpSecurity#addFilter(Filter filter)`2. 总结:1. 分析在上面Spring Security + Jwt...
一:RestApi接口增加JWT认证功能<br/>
用户填入用户名密码后,与数据库里存储的用户信息进行比对,如果通过,则认证成功。传统的方法是在认证通过后,创建sesstion,并给客户端返回cookie。
现在我们采用JWT来处理用户名密码的认证。区别在于,认证通过后,服务器生成一个token,将token返回给客户端,客户端以后的所有请求都需要在http头中指定该token。
服务器接收的请求后,会对token的合法性进行验证。验证的内容包括:
内容是一个正确的JWT格式
检查claims
创建一个类JWTLoginFilter,核心功能是在验证用户名密码正确后,生成一个token,并将token返回给客户端:
该类继承自UsernamePasswordAuthenticationFilter,重写了其中的2个方法:
attemptAuthentication :接收并解析用户凭证。
successfulAuthentication :用户成功登录后,这个方法会被调用,我们在这个方法里生成token。
二:授权验证
用户一旦登录成功后,会拿到token,后续的请求都会带着这个token,服务端会验证token的合法性。
创建JwtAuthenticationFilter类,我们在这个类中实现token的校验功能。
该类继承自BasicAuthenticationFilter,在doFilterInternal方法中,从http头的Authorization 项读取token数据,然后用Jwts包提供的方法校验token的合法性。
如果校验通过,就认为这是一个取得授权的合法请求。
三:SpringSecurity配置
通过SpringSecurity的配置,将上面的方法组合在一起。
这是标准的SpringSecurity配置内容,就不在详细说明。注意其中的
.addFilter(new JWTLoginFilter(authenticationManager()))
.addFilter(new JwtAuthenticationFilter(authenticationManager()))
这两行,将我们定义的JWT方法加入SpringSecurity的处理流程中。
四:简单测试
下面对我们的程序进行简单的验证:<br/>
1.请求获取用户列表接口:http://localhost:8080/users/userList接口,会收到403错误<br/>
"timestamp": 1518333248079,
"status": 403,
"error": "Forbidden",
"message": "Access Denied",
"path": "http://localhost:8080/users/userList"
curl http://localhost:8080/users/userList<br/>
原因就是因为这个url没有授权,所以返回403<br/>

2.注册一个新用户<br/>
curl -H "Content-Type: application/json" -X POST -d '{<br/>
"username": "admin",<br/>
"password": "password"<br/>
}' http://localhost:8080/users/signup<br/>

3.登录,会返回token,在http header中,Authorization: Bearer 后面的部分就是token<br/>
curl -i -H "Content-Type: application/json" -X POST -d '{<br/>
"username": "admin",<br/>
"password": "password"<br/>
}' http://localhost:8080/login<br/>
温馨提醒:这里的login方法是spring specurity框架提供的默认登录url

4.用登录成功后拿到的token再次请求/users/userList接口<br/>
4.1将请求中的XXXXXX替换成拿到的token<br/>
4.2这次可以成功调用接口了<br/>
curl -H "Content-Type: application/json"<br/>
-H "Authorization: Bearer XXXXXX"<br/>
"http://localhost:8080/users/userList"

在认证过程和访问授权前必须了解
spring Security如何知道我们要求所有用户都经过身份验证?
Spring Security如何知道我们想要支持基于表单的身份验证?因此必须了解Web
SecurityConfigurerAdapter配置类如何工作的。而且也必须了解清楚
filter的
顺序,才能更好了解其调用工作流程。
1. Web
SecurityConfigurerAdapter
Spring Security中的内置过滤器顺序是怎么维护的?我想很多开发者都对这个问题感兴趣。本篇我和大家一起探讨下这个问题。
HttpSecurity包含了一个成员变量FilterOrderRegistration,这个类是一个内置过滤器注册表。至于这些过滤器的作用,不是本文介绍的重点,有兴趣可以去看看FilterOrderRegistration的源码。
内置过滤器的顺序
FilterOrderRegistration维护了一个变量filterToOrder,它记录了类之间的顺序和上下之间的间隔
add_filter()(添加过滤器):
apply_filters( string $tag, mixed $value )
Call the functions added to a filter hook.
Description
The callback functions attached to filter hook $tag are invoked by calling t...
错就错在
addFilterAfter那里,我不应该用Authentication
Filter.class作为第二个参数。点进
addFilterAfter查看内部源码:
public Http
Security addFilterAfter(
Filter filter, Class<...