请求/oauth/token
访问到org.springframework.security.oauth2.provider.endpoint.TokenEndpoint
@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.");
}
String clientId = getClientId(principal);
ClientDetails authenticatedClient = getClientDetailsService().loadClientByClientId(clientId);
TokenRequest tokenRequest = getOAuth2RequestFactory().createTokenRequest(parameters, authenticatedClient);
if (clientId != null && !clientId.equals("")) {
// Only validate the client details if a client authenticated during this
// request.
if (!clientId.equals(tokenRequest.getClientId())) {
// double check to make sure that the client ID in the token request is the same as that in the
// authenticated client
throw new InvalidClientException("Given client ID does not match authenticated client");
}
}
if (authenticatedClient != null) {
oAuth2RequestValidator.validateScope(tokenRequest, authenticatedClient);
}
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");
}
if (isAuthCodeRequest(parameters)) {
// The scope was requested or determined during the authorization step
if (!tokenRequest.getScope().isEmpty()) {
logger.debug("Clearing scope of incoming token request");
tokenRequest.setScope(Collections.<String> emptySet());
}
}
if (isRefreshTokenRequest(parameters)) {
// A refresh token has its own default scopes, so we should ignore any added by the factory here.
tokenRequest.setScope(OAuth2Utils.parseParameterList(parameters.get(OAuth2Utils.SCOPE)));
}
OAuth2AccessToken token = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest);
if (token == null) {
throw new UnsupportedGrantTypeException("Unsupported grant type: " + tokenRequest.getGrantType());
}
return getResponse(token);
}
前面是一堆验证,我也没深入了解
OAuth2AccessToken token = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest);
这一句就是获取OAuth2AccessToken 这个对象了
点到getTokenGranter()中看一下,进入到AbstractEndpoint,就是获取TokenGranter,那么找一下,在哪里set的这个对象
public void setTokenGranter(TokenGranter tokenGranter) {
this.tokenGranter = tokenGranter;
}
protected TokenGranter getTokenGranter() {
return tokenGranter;
}
点setTokenGranter,发现在 AuthorizationServerEndpointsConfiguration 这个类中用到了
@Bean
public AuthorizationEndpoint authorizationEndpoint() throws Exception {
AuthorizationEndpoint authorizationEndpoint = new AuthorizationEndpoint();
FrameworkEndpointHandlerMapping mapping = getEndpointsConfigurer().getFrameworkEndpointHandlerMapping();
authorizationEndpoint.setUserApprovalPage(extractPath(mapping, "/oauth/confirm_access"));
authorizationEndpoint.setProviderExceptionHandler(exceptionTranslator());
authorizationEndpoint.setErrorPage(extractPath(mapping, "/oauth/error"));
authorizationEndpoint.setTokenGranter(tokenGranter());
authorizationEndpoint.setClientDetailsService(clientDetailsService);
authorizationEndpoint.setAuthorizationCodeServices(authorizationCodeServices());
authorizationEndpoint.setOAuth2RequestFactory(oauth2RequestFactory());
authorizationEndpoint.setOAuth2RequestValidator(oauth2RequestValidator());
authorizationEndpoint.setUserApprovalHandler(userApprovalHandler());
authorizationEndpoint.setRedirectResolver(redirectResolver());
return authorizationEndpoint;
}
@Bean
public TokenEndpoint tokenEndpoint() throws Exception {
TokenEndpoint tokenEndpoint = new TokenEndpoint();
tokenEndpoint.setClientDetailsService(clientDetailsService);
tokenEndpoint.setProviderExceptionHandler(exceptionTranslator());
tokenEndpoint.setTokenGranter(tokenGranter());
tokenEndpoint.setOAuth2RequestFactory(oauth2RequestFactory());
tokenEndpoint.setOAuth2RequestValidator(oauth2RequestValidator());
tokenEndpoint.setAllowedRequestMethods(allowedTokenEndpointRequestMethods());
return tokenEndpoint;
}
private TokenGranter tokenGranter() throws Exception {
return getEndpointsConfigurer().getTokenGranter();
}
public TokenGranter getTokenGranter() {
return tokenGranter();
}
private TokenGranter tokenGranter() {
if (tokenGranter == null) {
tokenGranter = new TokenGranter() {
private CompositeTokenGranter delegate;
@Override
public OAuth2AccessToken grant(String grantType, TokenRequest tokenRequest) {
if (delegate == null) {
delegate = new CompositeTokenGranter(getDefaultTokenGranters());
}
return delegate.grant(grantType, tokenRequest);
}
};
}
return tokenGranter;
}
这时候发现,实例化了一个CompositeTokenGranter,new CompositeTokenGranter(getDefaultTokenGranters());
private List<TokenGranter> getDefaultTokenGranters() {
ClientDetailsService clientDetails = clientDetailsService();
AuthorizationServerTokenServices tokenServices = tokenServices();
AuthorizationCodeServices authorizationCodeServices = authorizationCodeServices();
OAuth2RequestFactory requestFactory = requestFactory();
List<TokenGranter> tokenGranters = new ArrayList<TokenGranter>();
tokenGranters.add(new AuthorizationCodeTokenGranter(tokenServices, authorizationCodeServices, clientDetails,
requestFactory));
tokenGranters.add(new RefreshTokenGranter(tokenServices, clientDetails, requestFactory));
ImplicitTokenGranter implicit = new ImplicitTokenGranter(tokenServices, clientDetails, requestFactory);
tokenGranters.add(implicit);
tokenGranters.add(new ClientCredentialsTokenGranter(tokenServices, clientDetails, requestFactory));
if (authenticationManager != null) {
tokenGranters.add(new ResourceOwnerPasswordTokenGranter(authenticationManager, tokenServices,
clientDetails, requestFactory));
}
return tokenGranters;
}
new CompositeTokenGranter的时候,传参是一个List,add了五个对象类型
看一下这五个类和TokenGranter关系,都是继承了AbstractTokenGranter
grantType就是我们请求/oauth/token的参数,根据不同参数执行不同逻辑。
实例化CompositeTokenGranter之后,执行了grant方法
//实例化CompositeTokenGranter方法
public CompositeTokenGranter(List<TokenGranter> tokenGranters) {
this.tokenGranters = new ArrayList<TokenGranter>(tokenGranters);
}
public OAuth2AccessToken grant(String grantType, TokenRequest tokenRequest) {
for (TokenGranter granter : tokenGranters) {
OAuth2AccessToken grant = granter.grant(grantType, tokenRequest);
if (grant!=null) {
return grant;
}
}
return null;
}
我们发现,tokenGranters就是刚才那五个类,for循环去执行每个类中的grant。
比如
传参 grantType=“client_credentials”,就会执行到ClientCredentialsTokenGranter类中的grant
@Override
public OAuth2AccessToken grant(String grantType, TokenRequest tokenRequest) {
OAuth2AccessToken token = super.grant(grantType, tokenRequest);
if (token != null) {
DefaultOAuth2AccessToken norefresh = new DefaultOAuth2AccessToken(token);
// The spec says that client credentials should not be allowed to get a refresh token
if (!allowRefresh) {
norefresh.setRefreshToken(null);
}
token = norefresh;
}
return token;
}
首先就会执行父类的grant方法
当然有些类(比如password的ResourceOwnerPasswordTokenGranter类)就没有重写父类的grant方法,这时候就会执行到父类(AbstractTokenGranter)的grant方法
父类AbstractTokenGranter中的grant方法
public OAuth2AccessToken grant(String grantType, TokenRequest tokenRequest) {
if (!this.grantType.equals(grantType)) {
return null;
}
String clientId = tokenRequest.getClientId();
ClientDetails client = clientDetailsService.loadClientByClientId(clientId);
validateGrantType(grantType, client);
if (logger.isDebugEnabled()) {
logger.debug("Getting access token for: " + clientId);
}
return getAccessToken(client, tokenRequest);
}
这里面就有判断this.grantType是否等于请求中传参的grantType,this.grantType在实例化的时候就有赋值(ClientCredentialsTokenGranter构造方法中有super,父类也就赋值了)。如果为空,就继续前面的CompositeTokenGranter中的for循环。
不为空,验证client,grantType之后就是getAccessToken了
getAccessToken就会去判断是否存在accessToken,是否过期等等,也会发现refreshToken就是UUID,放入redis的话,key也是固定前缀,
RedisTokenStore中
private byte[] serializeKey(String object) {
return serialize(prefix + object);
}
object一般是access:token,但是这个serialize放了一个前缀prefix,可以初始化Bean,RedisTokenStore对该prefix赋值,我之前就是有的项目赋值了,有的没有,倒是token请求一直提示没有权限。
这时候就走完了整个流程,返回了accessToken这个对象
看代码会发现grantType=“client_credentials” 时,是没有返回 refreshToken的,加了一个判断
if (!allowRefresh) {
norefresh.setRefreshToken(null);
}
如果想返回该字段,可以赋值allowRefresh
没有太深入研究,如有错误,欢迎指出