Spring Security Oauth2 如何鉴别Token是否有效

版本

Spring Security Oauth2 : 2.3.5.RELEASE
Spring Boot 2.1.3
Spring Boot Starter: 2.1.3.RELEASE

解决思路

Spring Security 的两大功能认证鉴权,通过FilterChain(过滤器链)实现的,不同的请求经过不同的过滤器链。
Spring Security Oauth2 增加了拓展的过滤器链。
先观察整合Spring Security Oauth2 之后的一部分启动日志

o.s.s.web.DefaultSecurityFilterChain     : 
Creating filter chain: ----------------------------->【第一个过滤器链】
OrRequestMatcher [ 
    requestMatchers=[
        Ant [pattern='/oauth/token'],
        Ant [pattern='/oauth/token_key'], 
        Ant [pattern='/oauth/check_token']
    ]
], 
[
    org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@7e135a13, // 根据请求封装获取WebAsyncManager并注册
    org.springframework.security.web.context.SecurityContextPersistenceFilter@141c12a4, // 操作httpsession:有则加载 空则设置,SecurityContext的.set.clear
    org.springframework.security.web.header.HeaderWriterFilter@540abee6, // 请求头中添加相应信息
    org.springframework.security.web.authentication.logout.LogoutFilter@3aa062db,
    org.springframework.security.web.authentication.www.BasicAuthenticationFilter@3a2f0144, 
    org...security.web.savedrequest.RequestCacheAwareFilter@7c2ac578, // 内部维护了一个RequestCache,用于缓存HttpServletRequest
    org...security.web.servletapi.SecurityContextHolderAwareRequestFilter@6972facd, // 对ServletRequest进行了一次包装,+更加丰富的API 
    org...security.web.authentication.AnonymousAuthenticationFilter@4ee626ed, // 创建一个匿名用户存入到SecurityContextHolder 
    org...security.web.session.SessionManagementFilter@40c10fab, // 限制会话数量, session管理
    org...security.web.access.ExceptionTranslationFilter@2828c6c1, // 处理FilterSecurityInterceptor抛出的异常
    org...security.web.access.intercept.FilterSecurityInterceptor@19eadc0f // 获取权限信息调用manager鉴权
]
edFilterInvocationSecurityMetadataSource : Adding web access control expression 'permitAll', for ExactUrl [processUrl='/login?error']
edFilterInvocationSecurityMetadataSource : Adding web access control expression 'permitAll', for ExactUrl [processUrl='/login']
edFilterInvocationSecurityMetadataSource : Adding web access control expression 'permitAll', for ExactUrl [processUrl='/login']
edFilterInvocationSecurityMetadataSource : Adding web access control expression 'permitAll', for OrRequestMatcher [requestMatchers=[Ant [pattern='/my/logout', GET], Ant [pattern='/my/logout', POST], Ant [pattern='/my/logout', PUT], Ant [pattern='/my/logout', DELETE]]]
edFilterInvocationSecurityMetadataSource : Adding web access control expression 'permitAll', for ExactUrl [processUrl='/my/index']
edFilterInvocationSecurityMetadataSource : Adding web access control expression 'permitAll', for Ant [pattern='/swagger-ui.html']
edFilterInvocationSecurityMetadataSource : Adding web access control expression 'permitAll', for Ant [pattern='/v2/**']
edFilterInvocationSecurityMetadataSource : Adding web access control expression 'permitAll', for Ant [pattern='/webjars/**']
edFilterInvocationSecurityMetadataSource : Adding web access control expression 'permitAll', for Ant [pattern='/swagger-resources/**']
edFilterInvocationSecurityMetadataSource : Adding web access control expression 'permitAll', for Ant [pattern='/sys/callback/**']
edFilterInvocationSecurityMetadataSource : Adding web access control expression 'permitAll', for Ant [pattern='/**', OPTIONS]
edFilterInvocationSecurityMetadataSource : Adding web access control expression 'authenticated', for any request
o.s.s.w.a.i.FilterSecurityInterceptor    : Validated configuration attributes
o.s.s.w.a.i.FilterSecurityInterceptor    : Validated configuration attributes


o.s.s.web.DefaultSecurityFilterChain     : 
Creating filter chain:----------------------------->【第二个过滤器链】
org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfiguration$NotOAuthRequestMatcher@1f6f3d17,
[
    org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@73d8445d, 
    org.springframework.security.web.context.SecurityContextPersistenceFilter@2fbc6602,
    org.springframework.security.web.header.HeaderWriterFilter@5829f292,
    org.springframework.web.filter.CorsFilter@7e935b07,
    org.springframework.security.web.authentication.logout.LogoutFilter@75d6d4e4,
    org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter@41f3e913,
    org...security.web.authentication.UsernamePasswordAuthenticationFilter@43c3311,  // 登录认证
    org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@399639a2, 
    org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@75596840, 
    org.springframework.security.web.authentication.www.BasicAuthenticationFilter@7aae3de8, 
    org.springframework.security.web.savedrequest.RequestCacheAwareFilter@65547d87,
    org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@72febedd, 
    org.springframework.security.web.authentication.AnonymousAuthenticationFilter@13387479,
    org.springframework.security.web.session.SessionManagementFilter@70776a9a,
    org.springframework.security.web.access.ExceptionTranslationFilter@48404c4e,
    org.springframework.security.web.access.intercept.FilterSecurityInterceptor@72b8041e
]
edFilterInvocationSecurityMetadataSource : Adding web access control expression 'authenticated', for any request
o.s.s.w.a.i.FilterSecurityInterceptor    : Validated configuration attributes
o.s.s.w.a.i.FilterSecurityInterceptor    : Validated configuration attributes


o.s.s.web.DefaultSecurityFilterChain     : 
Creating filter chain: ----------------------------->【第三个过滤器链】
any request, 
[
    org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@4dc60fca, 
    org.springframework.security.web.context.SecurityContextPersistenceFilter@3e64049,
    org.springframework.security.web.header.HeaderWriterFilter@51e25fc4,
    org.springframework.security.web.csrf.CsrfFilter@2dc36543, // 验证请求是否包含csrf的token
    org.springframework.security.web.authentication.logout.LogoutFilter@342ca5c0,
    org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@7a4e80ea, 
    org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@5f9493e, 
    org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@76494a33, 
    org.springframework.security.web.authentication.www.BasicAuthenticationFilter@3aae8830, 
    org.springframework.security.web.savedrequest.RequestCacheAwareFilter@4f1ce0d9,
    org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@c439a81, 
    org.springframework.security.web.authentication.AnonymousAuthenticationFilter@788eddc0, 
    org.springframework.security.web.session.SessionManagementFilter@673dc1c6,
    org.springframework.security.web.access.ExceptionTranslationFilter@6605467a,
    org.springframework.security.web.access.intercept.FilterSecurityInterceptor@12352029
]

第一个过滤器链:/oauth/XXX的请求会进入
第二个过滤器链:oauth2对资源发请求时会进入
第三个过滤器链:剩下其他的请求会进入

当oauth2请求(Authorization请求头中Bearer协议的 access_token)进行访问时,会进入OAuth2AuthenticationProcessingFilter之中

public class OAuth2AuthenticationProcessingFilter implements Filter, InitializingBean {
	// ... 其他变量 和 方法
	
	public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain){
	
	    final HttpServletRequest request = (HttpServletRequest) req;
	    final HttpServletResponse response = (HttpServletResponse) res;
	
	    try {
	        //从请求中取出身份信息,将access_token 放入principal变量
	        Authentication authentication = tokenExtractor.extract(request);
	
	        if (authentication == null) {
	            // token信息为null,SecurityContextHolder 清空上下文
	        }
	        else {
	        	// request请求对象 放入authentication对象中
	            request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_VALUE, authentication.getPrincipal());
	            if (authentication instanceof AbstractAuthenticationToken) {
	                AbstractAuthenticationToken needsDetails = (AbstractAuthenticationToken) authentication;
	                needsDetails.setDetails(authenticationDetailsSource.buildDetails(request));
	            }
	            // 验证token身份信息
	            Authentication authResult = authenticationManager.authenticate(authentication);
	            eventPublisher.publishAuthenticationSuccess(authResult);
	            //将身份信息绑定到SecurityContextHolder中
	            SecurityContextHolder.getContext().setAuthentication(authResult);
	        }
	    }
	    catch (OAuth2Exception failed) {
	        // SecurityContextHolder 清空上下文, 然后直接返回
	        return;
	    }
	    chain.doFilter(request, response);
	}
}

但是,debug 发现存在多个authenticationManager实例,
然后,发现有好几个TokenServices
最后,还是直接使用InMemoryTokenStore或者RedisTokenStore来判断一个Token是否有效比较直接

以后有时间再继续分析。。。

原创文章 95 获赞 219 访问量 29万+

猜你喜欢

转载自blog.csdn.net/zimou5581/article/details/101051416
今日推荐