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);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章