oauth2源码解析/oauth/token干了些什么?
最近做了两个项目,基于各种原因,安全框架都是使用的Oauth2,之前对oauth2的了解也只是停留在使用的层面,知道有资源服务器,认证服务器,四种认证方式,但是对于其中的源码以及原因,没有深入的分析过,最近结合大师(程序员DD)的博客(http://blog.didispace.com/spr...),以及自己断点查看源码,对oauth的源码有了自己的分析,如有不周,还望各位大虾提出。我主要从以下几点分析:
1.入口接口:/oath/token;/oauth/check_token;
一.程序的入口:/oath/token
使用过oauth的童鞋都知道,当我们的oauth配置好之后,百分百会调用这个url去拿到我们的token,不论你是使用的get,还是post方式,都可以。他的入口在这个类:TokenEndpoint
@FrameworkEndpoint public class TokenEndpoint extends AbstractEndpoint { // ... //如果是get请求,走这里 @RequestMapping(value = "/oauth/token", method=RequestMethod.GET) public ResponseEntity<OAuth2AccessToken> getAccessToken(Principal principal, @RequestParam Map<String, String> parameters) throws HttpRequestMethodNotSupportedException { if (!allowedRequestMethods.contains(HttpMethod.GET)) { throw new HttpRequestMethodNotSupportedException("GET"); } //get请求最终还是调用了post请求 return postAccessToken(principal, parameters); } //post方式获取token @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."); } //拿到客户端id String clientId = getClientId(principal); ClientDetails authenticatedClient = getClientDetailsService().loadClientByClientId(clientId); //这一步把获取token的基础信息封装成了一个类 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))); } //重点:这一步调用了获取token的方法 OAuth2AccessToken token = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest); if (token == null) { throw new UnsupportedGrantTypeException("Unsupported grant type: " + tokenRequest.getGrantType()); } return getResponse(token); } //其他代码省略 ... }
我们顺着获取token的方法往下走,发现其调用了DefaultTokenServices的createAccessToken方法,里面则使用了tokenStore.getAccessToken(authentication)来获取的token,这个tokenStore具体是哪个实现类的对象,还要看我们在认证服务器(即继承了AuthorizationServerConfigurerAdapter类),里面的bean:tokenStore,我的如下:
@Bean public TokenStore tokenStore() { return new CrawlerRedisTokenStore(redisConnectionFactory); } //当然,也可以使用默认的几个实现类,比如InMemoryTokenStore,JdbcTokenStore, //JwtTokenStore,RedisTokenStore,我这里因为有其他需求,所有新建了一个实现类。
找到 tokenStore.getAccessToken(authentication)后,发现里面这句话,生成了token,我的token是存在redis的,他会先在reids里面找如果有token就拿出来,没有或者失效了,就重新生成一个.
OAuth2AccessToken accessToken = deserializeAccessToken(bytes);