OAuth2AuthenticationProcessingFilter
简介
授权认证服务通过认证后会返回Access Token,该token可用于请求资源服务(业务系统)的接口。我们需要把特定的信息放到请求头中,例如在请求头中写入Authorization: Bearer !xBYUEBY0N3o234N,Authorization为key,Bearer !xBYUEBY0N3o234N为value,!xBYUEBY0N3o234N是Access Token。请求经过OAuth2AuthenticationProcessingFilter后,过滤器中的认证管理器会调用配置的授权认证服务的check token接扣校验token是否有效,token有效则可以继续访问了。需要注意的是,对于资源认证服务Spring Security会把这个过滤器加入到过滤链里,但授权认证认证服务却不能。
源码分析
步骤1
笔者的Spring Cloud项目分ums[用户管理]服务以及auth[授权认证]服务,ums是一个业务系统,ums借助授权认证认证服务需要配置client-id,client-secret,token-info-uri等,token-info-uri即auth[授权认证]服务校验token的url,配置如下:
security:
oauth2:
client:
client-id: carp
client-secret: carp
resource:
id: carp-ums
token-info-uri: http://carp-auth:8002/oauth2/token/check
loadBalanced: true
步骤2
我们doFilter()方法中的代码进行分析,tokenExtractor.extract(request)从请求中取Bearer Token并包装成Authentication,然后调用authenticationManager.authenticate()向授权认证服务发起请求,对token进行认证。
认证成功后,发送认证成功事件,并把身份认证信息写入上下文,代码如下:
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException,
ServletException {
final boolean debug = logger.isDebugEnabled();
final HttpServletRequest request = (HttpServletRequest) req;
final HttpServletResponse response = (HttpServletResponse) res;
try {
//此处代码逻辑很简单
//Header中取出Authorization中的access token 并包装成Authentication,Authentication的principal就是token
Authentication authentication = tokenExtractor.extract(request);
//authentication不存在,清空上下文
if (authentication == null) {
if (stateless && isAuthenticated()) {
SecurityContextHolder.clearContext();
}
}
else {
//在request属性中写入OAuth2AuthenticationDetails.ACCESS_TOKEN_VALUE:xxxxx xxxx是token
request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_VALUE, authentication.getPrincipal());
//对于Bearer Token而言,authentication是PreAuthenticatedAuthenticationToken的实例,所以会执行到if分支里
if (authentication instanceof AbstractAuthenticationToken