Spring Security 实战干货:OAuth2登录获取Token的核心逻辑

公众号程序猿DD

共 5036字,需浏览 11分钟

 ·

2021-02-26 18:26

作者 | 码农小胖哥

来源 | https://mp.weixin.qq.com/s/zdTBdSVunqwVGx-spHjLjw

1. 前言

在上一篇Spring Security 实战干货:OAuth2 授权回调的核心认证流程中,我们讲了当第三方同意授权后会调用redirectUri发送回执给我们的服务器。我们的服务器拿到一个中间授信凭据会再次进行认证,目的是为了获取Token。而这个逻辑由OAuth2LoginAuthenticationProvider负责,经过上一文的分析后我们发现获取Token的具体逻辑由OAuth2AuthorizationCodeAuthenticationProvider来完成,今天就把它的流程搞清楚,来看看Spring Security OAuth2 认证授权获取Token的具体步骤。

注意:本Spring Security干货系列教程的 OAuth2 相关部分是在Spring Security 5.x版本的。

2. OAuth2AuthorizationCodeAuthenticationProvider

该类是AuthenticationProvider针对OAuth 2.0Authorization Code Grant模式的实现。关于AuthenticationProvider有必要简单强调一下,它已经多次在Spring Security 干货系列中出现,十分重要!一定要去看看相关的分析和使用,它是你根据业务扩展认证方式渠道的重要入口。

2.1 OAuth2AccessTokenResponseClient

在该实现中包含了一个OAuth2AccessTokenResponseClient成员变量,它抽象了通过tokenUri端点从认证服务器获取Token的细节。你可以根据OAuth 2.0常用的四种模式来进行实现它, 以达到根据不同的策略来获取Token的能力。

OAuth 2.0 四种模式的对应实现

Spring Security 5OAuth 2.0登录的配置中默认使用DefaultAuthorizationCodeTokenResponseClient。如果你想使用自定义实现的话可以通过HttpSecurity来配置:

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.oauth2Login()
                    .tokenEndpoint()
                // 注入自定义的 OAuth2AccessTokenResponseClient
                    .accessTokenResponseClient(authorizationCodeTokenResponseClient);
            // 其它省略

        }

接下来我们看看DefaultAuthorizationCodeTokenResponseClient实现的获取Token的逻辑:

@Override
public OAuth2AccessTokenResponse getTokenResponse(OAuth2AuthorizationCodeGrantRequest authorizationCodeGrantRequest) {
   Assert.notNull(authorizationCodeGrantRequest, "authorizationCodeGrantRequest cannot be null");
// 1. 封装调用tokenUri所需要的请求参数RequestEntity
   RequestEntity<?> request = this.requestEntityConverter.convert(authorizationCodeGrantRequest);

   ResponseEntity<OAuth2AccessTokenResponse> response;
   try {
   // 2. 通过RestTemplate 发起请求获取 OAuth2AccessTokenResponse
      response = this.restOperations.exchange(request, OAuth2AccessTokenResponse.class);
   } catch (RestClientException ex) {
      OAuth2Error oauth2Error = new OAuth2Error(INVALID_TOKEN_RESPONSE_ERROR_CODE,
            "An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: " + ex.getMessage(), null);
      throw new OAuth2AuthorizationException(oauth2Error, ex);
   }

  // 3. 解析 ResponseEntity 组织返回值 OAuth2AccessTokenResponse
   OAuth2AccessTokenResponse tokenResponse = response.getBody();

   if (CollectionUtils.isEmpty(tokenResponse.getAccessToken().getScopes())) {

      // originally requested by the client in the Token Request
      tokenResponse = OAuth2AccessTokenResponse.withResponse(tokenResponse)
            .scopes(authorizationCodeGrantRequest.getClientRegistration().getScopes())
            .build();
   }

   return tokenResponse;
}

这里的方式跟我另一个开源项目Payment Spring Boot的请求方式异曲同工,都是三个步骤:

  1. 组织参数RequestEntity
  2. RestOperations发起请求。
  3. 解析ResponseEntity组织返回值。

如果有些的OAuth 2.0认证服务器获取Token的方式比较特殊你可以自行实现OAuth2AccessTokenResponseClient

3. 总结

OAuth2AccessTokenResponseClientOAuth2AuthorizationCodeAuthenticationProvider的核心要点。搞清楚它的作用和机制就可以了。这里我们总结一下OAuth2AuthorizationCodeAuthenticationProvider的认证过程:

  1. 检测未授信OAuth2AuthorizationCodeAuthenticationToken的状态是否合法。
  2. 通过OAuth2AccessTokenResponseClient请求OAuth 2.0认证服务器获取Token等信息。
  3. 组装认证过的授信OAuth2AuthorizationCodeAuthenticationToken返回。

到此OAuth 2.0的登录流程就搞清楚了,读者可通过系列文章进行学习批判。我是:码农小胖哥,多多关注,获取实用的编程干货。

推荐关注本文作者:码农小胖哥

分享高质量编程知识,探讨IT人生

技术干货,实战技巧,面试技巧,前沿资讯一个都不能少


往期推荐

上云上的差点破产是什么体验?

本科毕业出国率下降,考研or保研?条条大路通「内卷」

一个员工的离职,背后都意味着什么?

彻底解决 gcr、quay、DockerHub 镜像下载难题!

合格的后端Coder都应该写好UT和Mock测试

Spring Boot 2.4.3、2.3.9 版本发布,你准备好了吗?


浏览 91
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报