最近作了兩個項目,基於各類緣由,安全框架都是使用的Oauth2,以前對oauth2的瞭解也只是停留在使用的層面,知道有資源服務器,認證服務器,四種認證方式,可是對於其中的源碼以及緣由,沒有深刻的分析過,最近結合大師(程序員DD)的博客(http://blog.didispace.com/spr...),以及本身斷點查看源碼,對oauth的源碼有了本身的分析,若有不周,還望各位大蝦提出。我主要從如下幾點分析:程序員
1.入口接口:/oath/token;/oauth/check_token;
一.程序的入口:/oath/tokenredis
使用過oauth的童鞋都知道,當咱們的oauth配置好以後,百分百會調用這個url去拿到咱們的token,不論你是使用的get,仍是post方式,均可以。他的入口在這個類:TokenEndpointspring
@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);