Oauth2的资源服务器核心源码分析
2021/8/22 17:06:14
本文主要是介绍Oauth2的资源服务器核心源码分析,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
资源服务器核心源码分析
OAuth2AuthenticationProcessingFilter
资源服务器的核心是OAuth2AuthenticationProcessingFilter过滤器。它被插到配置为资源端口的过滤器链中,主要功能是获取请求中携带的access_token中,通过access_token提取OAuth2Authentication并存入Spring Security上下文。
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 { //提取请求携带的token,构建一个认证的Authentication对象 Authentication authentication = tokenExtractor.extract(request); if (authentication == null) { if (stateless && isAuthenticated()) { if (debug) { logger.debug("Clearing security context."); } SecurityContextHolder.clearContext(); } if (debug) { logger.debug("No token in request, will continue chain."); } } else { request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_VALUE, authentication.getPrincipal()); if (authentication instanceof AbstractAuthenticationToken) { AbstractAuthenticationToken needsDetails = (AbstractAuthenticationToken) authentication; needsDetails.setDetails(authenticationDetailsSource.buildDetails(request)); } //获取token携带的认证信息,OAuth2AuthenticationManager主要做了3件事 //1.通过token获取用户的OAuth2Authentication对象 //2.验证访问资源resourceId是否符合范围 //3.验证客户端访问的scope Authentication authResult = authenticationManager.authenticate(authentication); if (debug) { logger.debug("Authentication success: " + authResult); } eventPublisher.publishAuthenticationSuccess(authResult); //将当前的Authentication放入到Context中,访问后面的资源 SecurityContextHolder.getContext().setAuthentication(authResult); } } catch (OAuth2Exception failed) { SecurityContextHolder.clearContext(); if (debug) { logger.debug("Authentication request failed: " + failed); } eventPublisher.publishAuthenticationFailure(new BadCredentialsException(failed.getMessage(), failed), new PreAuthenticatedAuthenticationToken("access-token", "N/A")); authenticationEntryPoint.commence(request, response, new InsufficientAuthenticationException(failed.getMessage(), failed)); return; } chain.doFilter(request, response); }
- TokenExtractor的默认实现类BearerTokenExtractor
- AuthenticationManager的默认实现类是OAuth2AuthenticationManager
TokenExtractor
接口的功能是提取请求中包含的access_token,目前只有一个实现类:BearerTokenExtractor,它只用于提取Bearer类型的access_token。请求中携带的access_token参数即可以放在HTTP请求头中,也可以在HTTP请求参数中。核心源码如下:
@Override public Authentication extract(HttpServletRequest request) { String tokenValue = extractToken(request); if (tokenValue != null) { PreAuthenticatedAuthenticationToken authentication = new PreAuthenticatedAuthenticationToken(tokenValue, ""); return authentication; } return null; } protected String extractToken(HttpServletRequest request) { // 首先从header中解析access_token String token = extractHeaderToken(request); // 然后从request parameter中access_token if (token == null) { logger.debug("Token not found in headers. Trying request parameters."); token = request.getParameter(OAuth2AccessToken.ACCESS_TOKEN); if (token == null) { logger.debug("Token not found in request parameters. Not an OAuth2 request."); } else { request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_TYPE, OAuth2AccessToken.BEARER_TYPE); } } return token; }
OAuth2AuthenticationManager
public Authentication authenticate(Authentication authentication) throws AuthenticationException { if (authentication == null) { throw new InvalidTokenException("Invalid token (token not found)"); } else { String token = (String)authentication.getPrincipal(); //借助tokenServices,根据token加载身份信息 OAuth2Authentication auth = this.tokenServices.loadAuthentication(token); if (auth == null) { throw new InvalidTokenException("Invalid token: " + token); } else { Collection<String> resourceIds = auth.getOAuth2Request().getResourceIds(); if (this.resourceId != null && resourceIds != null && !resourceIds.isEmpty() && !resourceIds.contains(this.resourceId)) { throw new OAuth2AccessDeniedException("Invalid token does not contain resource id (" + this.resourceId + ")"); } else { this.checkClientDetails(auth); if (authentication.getDetails() instanceof OAuth2AuthenticationDetails) { OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails)authentication.getDetails(); if (!details.equals(auth.getDetails())) { details.setDecodedDetails(auth.getDetails()); } } auth.setDetails(authentication.getDetails()); auth.setAuthenticated(true); return auth; } } } }
其中,最关键的tokenServices是ResourceServerTokenServices的实例。ResourceServerTokenServices接口的最主要的2个实现类是RemoteTokenServices和DefaultTokenServices。下面的断点中,我用的是远程调用,RemoteTokenServices
下面是我部分断点的图,比较简单,就不说明了,其中pig的官网也有说明,连接:pig 校验令牌详解 【原理】 · 语雀 (yuque.com)
这篇关于Oauth2的资源服务器核心源码分析的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-06-26结对编程到底难不难?答案在这里
- 2024-06-19《2023版Java工程师》课程升级公告
- 2024-06-15matplotlib作图不显示3D图,怎么办?
- 2024-06-1503-Loki 日志监控
- 2024-06-1504-让LLM理解知识 -Prompt
- 2024-06-05做软件测试需要懂代码吗?
- 2024-06-0514-ShardingSphere的分布式主键实现
- 2024-06-03为什么以及如何要进行架构设计权衡?
- 2024-05-31全网首发第二弹!软考2024年5月《软件设计师》真题+解析+答案!(11-20题)
- 2024-05-31全网首发!软考2024年5月《软件设计师》真题+解析+答案!(21-30题)