Spring Security 實(shí)戰(zhàn)干貨:OAuth2登錄獲取Token的核心邏輯

作者 | 碼農(nóng)小胖哥
1. 前言
在上一篇Spring Security 實(shí)戰(zhàn)干貨:OAuth2 授權(quán)回調(diào)的核心認(rèn)證流程中,我們講了當(dāng)?shù)谌酵馐跈?quán)后會調(diào)用redirectUri發(fā)送回執(zhí)給我們的服務(wù)器。我們的服務(wù)器拿到一個中間授信憑據(jù)會再次進(jìn)行認(rèn)證,目的是為了獲取Token。而這個邏輯由OAuth2LoginAuthenticationProvider負(fù)責(zé),經(jīng)過上一文的分析后我們發(fā)現(xiàn)獲取Token的具體邏輯由OAuth2AuthorizationCodeAuthenticationProvider來完成,今天就把它的流程搞清楚,來看看Spring Security OAuth2 認(rèn)證授權(quán)獲取Token的具體步驟。
?
注意:本Spring Security干貨系列教程的 OAuth2 相關(guān)部分是在Spring Security 5.x版本的。
2. OAuth2AuthorizationCodeAuthenticationProvider
該類是AuthenticationProvider針對OAuth 2.0中Authorization Code Grant模式的實(shí)現(xiàn)。關(guān)于AuthenticationProvider有必要簡單強(qiáng)調(diào)一下,它已經(jīng)多次在Spring Security 干貨系列中出現(xiàn),十分重要!一定要去看看相關(guān)的分析和使用,它是你根據(jù)業(yè)務(wù)擴(kuò)展認(rèn)證方式渠道的重要入口。
2.1 OAuth2AccessTokenResponseClient
在該實(shí)現(xiàn)中包含了一個OAuth2AccessTokenResponseClient成員變量,它抽象了通過tokenUri端點(diǎn)從認(rèn)證服務(wù)器獲取Token的細(xì)節(jié)。你可以根據(jù)OAuth 2.0常用的四種模式來進(jìn)行實(shí)現(xiàn)它, 以達(dá)到根據(jù)不同的策略來獲取Token的能力。
OAuth 2.0 四種模式的對應(yīng)實(shí)現(xiàn)
在Spring Security 5中OAuth 2.0登錄的配置中默認(rèn)使用DefaultAuthorizationCodeTokenResponseClient。如果你想使用自定義實(shí)現(xiàn)的話可以通過HttpSecurity來配置:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.oauth2Login()
.tokenEndpoint()
// 注入自定義的 OAuth2AccessTokenResponseClient
.accessTokenResponseClient(authorizationCodeTokenResponseClient);
// 其它省略
}
接下來我們看看DefaultAuthorizationCodeTokenResponseClient實(shí)現(xiàn)的獲取Token的邏輯:
@Override
public OAuth2AccessTokenResponse getTokenResponse(OAuth2AuthorizationCodeGrantRequest authorizationCodeGrantRequest) {
Assert.notNull(authorizationCodeGrantRequest, "authorizationCodeGrantRequest cannot be null");
// 1. 封裝調(diào)用tokenUri所需要的請求參數(shù)RequestEntity
RequestEntity<?> request = this.requestEntityConverter.convert(authorizationCodeGrantRequest);
ResponseEntity<OAuth2AccessTokenResponse> response;
try {
// 2. 通過RestTemplate 發(fā)起請求獲取 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;
}
這里的方式跟我另一個開源項(xiàng)目Payment Spring Boot的請求方式異曲同工,都是三個步驟:
組織參數(shù) RequestEntity。RestOperations發(fā)起請求。解析 ResponseEntity組織返回值。
如果有些的OAuth 2.0認(rèn)證服務(wù)器獲取Token的方式比較特殊你可以自行實(shí)現(xiàn)OAuth2AccessTokenResponseClient。
3. 總結(jié)
OAuth2AccessTokenResponseClient是OAuth2AuthorizationCodeAuthenticationProvider的核心要點(diǎn)。搞清楚它的作用和機(jī)制就可以了。這里我們總結(jié)一下OAuth2AuthorizationCodeAuthenticationProvider的認(rèn)證過程:
檢測未授信 OAuth2AuthorizationCodeAuthenticationToken的狀態(tài)是否合法。通過 OAuth2AccessTokenResponseClient請求OAuth 2.0認(rèn)證服務(wù)器獲取Token等信息。組裝認(rèn)證過的授信 OAuth2AuthorizationCodeAuthenticationToken返回。
到此OAuth 2.0的登錄流程就搞清楚了,讀者可通過系列文章進(jìn)行學(xué)習(xí)批判。我是:碼農(nóng)小胖哥,多多關(guān)注,獲取實(shí)用的編程干貨。
推薦關(guān)注本文作者:碼農(nóng)小胖哥
分享高質(zhì)量編程知識,探討IT人生
往期推薦
