Spring Security 實戰乾貨:OAuth2登入獲取Token的核心邏輯

碼農小胖哥發表於2021-02-23

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的登入流程就搞清楚了,讀者可通過系列文章進行學習批判。我是:碼農小胖哥,多多關注,獲取實用的程式設計乾貨。

關注公眾號:Felordcn 獲取更多資訊

個人部落格:https://felord.cn

相關文章