一,先看流程图
二,步骤解析
1,首先从获取授权码的请求路径/oauth/token入手
主要流程为获取ClientDetails-》认证并返回授权信息-》返回获取到的token
@RequestMapping(value = "/oauth/token", method=RequestMethod.POST)
public ResponseEntity<OAuth2AccessToken> postAccessToken(Principal principal, @RequestParam
Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
。。。
String clientId = getClientId(principal);
ClientDetails authenticatedClient = getClientDetailsService().loadClientByClientId(clientId);
//获取ClientDetails(第三方应用)
//loadClientByClientId 的 sql语句 :select client_id, client_secret,。。。 from oauth_client_details where client_id = ?
TokenRequest tokenRequest = getOAuth2RequestFactory().createTokenRequest(parameters, authenticatedClient);//组装tokenRequest
。。。
//这里根据传过来的认授权模式(密码模式,授权码模式等),认证并返回授权信息
OAuth2AccessToken token = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest);
if (token == null) {
throw new UnsupportedGrantTypeException("Unsupported grant type: " + tokenRequest.getGrantType());
}
return getResponse(token);//返回获取到的token
}
2,查看认证并返回授权信息的方法, getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest);
public class CompositeTokenGranter implements TokenGranter {
private final List<TokenGranter> tokenGranters;
public OAuth2AccessToken grant(String grantType, TokenRequest tokenRequest) {
for (TokenGranter granter : tokenGranters) {
OAuth2AccessToken grant = granter.grant(grantType, tokenRequest);//找到对应的生成token授权模式,并认证
if (grant!=null) {
return grant;
}
}
return null;
}
public OAuth2AccessToken grant(String grantType, TokenRequest tokenRequest) {
。。。
String clientId = tokenRequest.getClientId();
ClientDetails client = clientDetailsService.loadClientByClientId(clientId);
validateGrantType(grantType, client);
return getAccessToken(client, tokenRequest); //这里
}
protected OAuth2AccessToken getAccessToken(ClientDetails client, TokenRequest tokenRequest) {
return tokenServices.createAccessToken(getOAuth2Authentication(client, tokenRequest));// 不同的授权模式getOAuth2Authentication
}
3,上面的tokenServices.createAccessToken(getOAuth2Authentication(client, tokenRequest)); 有两个方法
首先看内层方法getOAuth2Authentication(client, tokenRequest),该方法不同的授权模式有不同的实现
以密码授权模式ResourceOwnerPasswordTokenGranter 为例,
进入该类的getOAuth2Authentication方法
@Override
protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
Map<String, String> parameters = new LinkedHashMap<String, String>(tokenRequest.getRequestParameters());
String username = parameters.get("username");
String password = parameters.get("password");
parameters.remove("password");
Authentication userAuth = new UsernamePasswordAuthenticationToken(username, password);
((AbstractAuthenticationToken) userAuth).setDetails(parameters);
try {
userAuth = authenticationManager.authenticate(userAuth);//这里
}
。。。
OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest);
return new OAuth2Authentication(storedOAuth2Request, userAuth); //生成OAuth2Authentication
}
4,上面的 userAuth = authenticationManager.authenticate(userAuth); 就是账号密码登陆的逻辑,取得认证信息。详看springsecurity源码(密码登陆) 第三步
5,取得认证信息后,返回再看 tokenServices.createAccessToken(getOAuth2Authentication(client, tokenRequest)); 的外层方法createAccessToken方法
跟进DefaultTokenServices的createAccessToken方法
@Transactional
public OAuth2AccessToken createAccessToken(OAuth2Authentication authentication) throws AuthenticationException {
OAuth2AccessToken existingAccessToken = tokenStore.getAccessToken(authentication);// 获取OAuth2AccessToken 从jdbc,jwt,redis,inmemory
if (existingAccessToken != null) {
。。。。。
return existingAccessToken; //如果存在就返回
}
OAuth2RefreshToken refreshToken = null;
。。。
OAuth2AccessToken accessToken = createAccessToken(authentication, refreshToken);//不存在就进入这里
tokenStore.storeAccessToken(accessToken, authentication);
。。。
refreshToken = accessToken.getRefreshToken();
if (refreshToken != null) {
tokenStore.storeRefreshToken(refreshToken, authentication);
}
return accessToken;
}
6,查看 createAccessToken(authentication, refreshToken);
该方法生成最终的OAuth2AccessToken,并返回,
回到第1步的return getResponse(token); 返回给客户端
private OAuth2AccessToken createAccessToken(OAuth2Authentication authentication, OAuth2RefreshToken refreshToken) {
DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(UUID.randomUUID().toString());
int validitySeconds = getAccessTokenValiditySeconds(authentication.getOAuth2Request());
if (validitySeconds > 0) {
token.setExpiration(new Date(System.currentTimeMillis() + (validitySeconds * 1000L)));
}
token.setRefreshToken(refreshToken);
token.setScope(authentication.getOAuth2Request().getScope());
return accessTokenEnhancer != null ? accessTokenEnhancer.enhance(token, authentication) : token;//自定义token
}