preface
This paper mainly studies the token acquisition process of spring security oauth2. There are five ways to obtain tokens, of which the authorization mode is the most complex. Therefore, this paper studies the token acquisition based on the authorization mode. Without much nonsense, let's go to the core source code flow chart first!
TokenEndpoint: it is the entry controller, that is, the interface where we request / oauth/token to return the token
ClientDetailsService: This is a bit similar to the UserDetailsService in spring security. UserDetailsService reads user information, and
ClientDetailsService reads the client information, that is, according to the username and password stored in Authorization when we send the / oauth/token request. Note that this is not the user's but the client's endpoint information
ClientDetails: This is used to store the client information queried by ClientDetailsService
TokenRequest: This is also used to encapsulate some other information in the request, such as grant_type,client_id, and client details will also be put into it
TokenGrande: this interface encapsulates the default authorization mode in 5 provided by spring security oauth2. This interface will be based on the incoming grant_type implements different authorization logic. No matter which authorization mode is adopted here, two objects OAuth2Request and Authentication will be generated. Finally, the two objects will be combined into oauthauthentication
OAuth2Request: This is to integrate the information of ClientDetails and TokenRequest
Authentication: This is to store the current authorized login user information, which is actually the user information obtained from UserDetailsService
OAuth2Authentication: this object is the information of the currently authorized login user, the currently authorized client information, the authorization mode, and some other parameters in the authorization. Finally, these data will be encapsulated in this object
AuthorizationServerTokenServices: this interface actually uses the assembled oauthauthentication to generate tokens according to the TokenEnhance generation policy and store tokens according to the TokenStore storage method
OAuth2AccessToken: This is the final returned Token information
1, TokenEndpoint
1.1 TokenEndpoint attribute
@FrameworkEndpoint public class TokenEndpoint extends AbstractEndpoint { private OAuth2RequestValidator oAuth2RequestValidator = new DefaultOAuth2RequestValidator(); private Set<HttpMethod> allowedRequestMethods = new HashSet<HttpMethod>(Arrays.asList(HttpMethod.POST)); private WebResponseExceptionTranslator<OAuth2Exception> providerExceptionHandler = new DefaultWebResponseExceptionTranslator(); private TokenGranter tokenGranter; private ClientDetailsService clientDetailsService; private OAuth2RequestFactory oAuth2RequestFactory; private OAuth2RequestFactory defaultOAuth2RequestFactory; }
1.2 TokenEndpoint initialization
The initialization of TokenEndpoint occurs in the configuration class AuthorizationServerEndpointsConfiguration, which is imported from the annotation @ EnableAuthorizationServer
@Configuration @Import(TokenKeyEndpointRegistrar.class) public class AuthorizationServerEndpointsConfiguration { private AuthorizationServerEndpointsConfigurer endpoints = new AuthorizationServerEndpointsConfigurer(); @Autowired private ClientDetailsService clientDetailsService; @Autowired private List<AuthorizationServerConfigurer> configurers = Collections.emptyList(); @Bean public TokenEndpoint tokenEndpoint() throws Exception { TokenEndpoint tokenEndpoint = new TokenEndpoint(); tokenEndpoint.setClientDetailsService(clientDetailsService);//Direct injection tokenEndpoint.setProviderExceptionHandler(exceptionTranslator()); tokenEndpoint.setTokenGranter(tokenGranter()); tokenEndpoint.setOAuth2RequestFactory(oauth2RequestFactory()); tokenEndpoint.setOAuth2RequestValidator(oauth2RequestValidator()); tokenEndpoint.setAllowedRequestMethods(allowedTokenEndpointRequestMethods()); return tokenEndpoint; }
1.3 postAccessToken
Because the url to get the token is / oauth/token, he will enter the following code
@FrameworkEndpoint public class TokenEndpoint extends AbstractEndpoint { private OAuth2RequestValidator oAuth2RequestValidator = new DefaultOAuth2RequestValidator(); private Set<HttpMethod> allowedRequestMethods = new HashSet<HttpMethod>(Arrays.asList(HttpMethod.POST)); @RequestMapping(value = "/oauth/token", method=RequestMethod.POST) public ResponseEntity<OAuth2AccessToken> postAccessToken(Principal principal, @RequestParam Map<String, String> parameters) throws HttpRequestMethodNotSupportedException { //The interface must be authenticated if (!(principal instanceof Authentication)) {throw new InsufficientAuthenticationException("");} //Remove the clientId from the request header String clientId = getClientId(principal); //Read database endpoint information through ClientDetailsService ClientDetails authenticatedClient = getClientDetailsService().loadClientByClientId(clientId); //Encapsulate endpoint information + request other parameters 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 is requested or determined in the authorization step if (!tokenRequest.getScope().isEmpty()) { tokenRequest.setScope(Collections.<String> emptySet()); } } if (isRefreshTokenRequest(parameters)) { // The refresh token has its own default scope, so we should ignore any tags added here by the factory. tokenRequest.setScope(OAuth2Utils.parseParameterList(parameters.get(OAuth2Utils.SCOPE))); } //Core method: get the token and assemble it into OAuth2AccessToken OAuth2AccessToken token = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest); if (token == null) { throw new UnsupportedGrantTypeException("Unsupported grant type: " + tokenRequest.getGrantType()); } return getResponse(token); } }