通過請求 oauth/token 來獲取 token丸冕。大致為以下流程:
- 從 principal 中獲取 clientId, 進(jìn)而裝載 ClientDetails 。
- 從 parameters 中獲取 clientId薛窥、scope胖烛、grantType 以組裝 TokenRequest。
- 校驗 Client 信息诅迷。
- 根據(jù) grantType 設(shè)置 TokenRequest 的 scope洪己。
- 通過令牌授予者獲取 Token。
下面我們通過源碼來學(xué)習(xí)整個流程竟贯。
@FrameworkEndpoint
public class TokenEndpoint extends AbstractEndpoint {
// 以下是核心部分代碼...
@RequestMapping(value = "/oauth/token", method=RequestMethod.POST)
public ResponseEntity<OAuth2AccessToken> postAccessToken(Principal principal, @RequestParam Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
if (!(principal instanceof Authentication)) {
throw new InsufficientAuthenticationException(
"There is no client authentication. Try adding an appropriate authentication filter.");
}
// 1. 從 principal 中獲取 clientId, 進(jìn)而 load client 信息
String clientId = getClientId(principal);
ClientDetails authenticatedClient = getClientDetailsService().loadClientByClientId(clientId);
// 2. 從 parameters 中拿 clientId、scope逝钥、grantType 組裝 TokenRequest
TokenRequest tokenRequest = getOAuth2RequestFactory().createTokenRequest(parameters, authenticatedClient);
// 3. 校驗 client 信息
if (clientId != null && !clientId.equals("")) {
if (!clientId.equals(tokenRequest.getClientId())) {
// 雙重校驗: 確保從 principal 拿到的 client 信息與根據(jù) parameters 得到的 client 信息一致
throw new InvalidClientException("Given client ID does not match authenticated client");
}
}
if (authenticatedClient != null) {
oAuth2RequestValidator.validateScope(tokenRequest, authenticatedClient);
}
// 4. 根據(jù) grantType 設(shè)置 TokenRequest 的 scope屑那。
// 授權(quán)類型有: password 模式、authorization_code 模式艘款、refresh_token 模式持际、client_credentials 模式、implicit 模式
if (!StringUtils.hasText(tokenRequest.getGrantType())) {
throw new InvalidRequestException("Missing grant type");
}
if (tokenRequest.getGrantType().equals("implicit")) {
throw new InvalidGrantException("Implicit grant type not supported from token endpoint");
}
// 如果是授權(quán)碼模式, 則清空 scope哗咆。 因為授權(quán)請求過程會確定 scope, 所以沒必要傳
if (isAuthCodeRequest(parameters)) {
if (!tokenRequest.getScope().isEmpty()) {
logger.debug("Clearing scope of incoming token request");
tokenRequest.setScope(Collections.<String> emptySet());
}
}
// 如果是刷新 Token 模式, 解析并設(shè)置 scope
if (isRefreshTokenRequest(parameters)) {
tokenRequest.setScope(OAuth2Utils.parseParameterList(parameters.get(OAuth2Utils.SCOPE)));
}
// 5. 通過令牌授予者獲取 token
OAuth2AccessToken token = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest);
if (token == null) {
throw new UnsupportedGrantTypeException("Unsupported grant type: " + tokenRequest.getGrantType());
}
return getResponse(token);
}
// ...
}
該系列文章:
Spring Security OAuth2 源碼分析1 - TokenEndpoint
Spring Security OAuth2 源碼分析2 - TokenGranter
Spring Security OAuth2 源碼分析3 - TokenServices
持續(xù)更新中...