OAuth2 内置断点生成Token源码解析

在我们现实的开发者,当我们使用oauth的时候,当需要生成token时, 只需要去调用/oauth/token,但是他具体做了什么?就可以实现今天我们就来一探究竟

TokenEndpoint

不难看出最终调用的时TokenEndpoint这个类,那么我们来分析学习一下这个类

首先映入眼帘的时@FrameworkEndpoint,@FrameworkEndpoint@Controller的同义词, 但仅用于框架提供的端点(因此它永远不会与用@Controller定义的用户自己的端点冲突)

框架为我们提供了POSTGET请求,但最终走的都是POST请求

@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, 进而 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 信息与根据 parameters 得到的 client 信息一致
                throw new InvalidClientException("Given client ID does not match authenticated client");
            }
        }
        if (authenticatedClient != null) {
            oAuth2RequestValidator.validateScope(tokenRequest, authenticatedClient);
        }
 
        // 4. 根据 grantType 设置 TokenRequest 的 scope。
        // 授权类型有: 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");
        }
 
        // 如果是授权码模式, 则清空 scope。 因为授权请求过程会确定 scope, 所以没必要传
        if (isAuthCodeRequest(parameters)) {
            if (!tokenRequest.getScope().isEmpty()) {
                logger.debug("Clearing scope of incoming token request");
                tokenRequest.setScope(Collections.<String> emptySet());
            }
        }
 
        // 如果是刷新 Token 模式, 解析并设置 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);
    }
    // ...
}

这里我们来看一下生成token的逻辑,也就是 OAuth2AccessToken token = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest); 这段代码,调用的时 AbstractTokenGranter

getOAuth2Authentication 有三种方式的实现

密码模式下生成Token

OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest); 最终调用的是TokenRequest

我们知道了密码模式下的createOAuth2Request,这是我们在回到createAccessToken,他最终调用的是DefaultTokenServices的方法,

tokenStore 的多种实现方式 TokenStore

  • MyTokenEnhancerChain

  • MyJwtAccessTokenConverter

授权码模式下生成Token

如何让生成token,与上面的过程是一样的

Last updated

Was this helpful?