/oauth/token

本文详细探讨了SpringSecurityOAuth2.0框架中TokenEndpoint的实现,重点关注授权模式下的token获取流程,包括ClientDetailsService的作用、TokenRequest的构建和多种授权机制的处理。
摘要由CSDN通过智能技术生成
 /oauth/token 是oauth2.0框架自带的路径在TokenEndpoint类中

 spring-security-oauth里面的org.springframework.sercurity.ouath2.provider.endpoit

本文主要研究Spring Security Oauth2 token获取流程,token的获取方式有5种,其中授权模式最复杂,故本文以授权模式为基准研究token的获取,废话不多说,先上一张核心源码流程图!

TokenEndpoint: 是入口controller,也就是我们请求/oauth/token返回token的接口

ClientDetailsService: 这个就有点类似SpringSecurity中的UserDetailsService,UserDetailsService是读取用户信息的,而
ClientDetailsService则是读取客户端信息的,也就是根据我们发送/oauth/token请求是存放在Authorization中的username和password,注意这个不是用户的,而是客户端的端点信息

ClientDetails: 这个就是用来存储ClientDetailsService查询到的客户端信息的

TokenRequest: 这也是用来封装请求中的一些其他信息如grant_type、client_id等,同时也会将ClientDetails放入到这里面

TokenGrande: 这个接口封装的就是SpringSecurityOAuth2提供的5中默认授权模式,这个接口中会根据传入的grant_type执行不同的授权逻辑,这里不管走那种授权模式,都会产生两个对象OAuth2Request和Authentication,最终这两个对象会组合为OAuth2Authentication

OAuth2Request: 这个就是将ClientDetails和TokenRequest的信息做一个整合

Authentication: 这个就是存储当前授权登录的用户信息,实际上也就是从UserDetailsService中得到的用户信息

OAuth2Authentication: 这个对象就是将当前授权登录的用户信息,当前授权的是那个客户端信息,还有授权模式是什么,还有一些授权中的其他参数,最终这些数据都会被封装在这个对象中

AuthorizationServerTokenServices: 这个接口实际上就是使用组装好的OAuth2Authentication按照TokenEnhance生成策略生成Token,按照TokenStore存储方式存储Token

OAuth2AccessToken: 这个就是最终返回去的Token信息一、TokenEndpoint
1.1 TokenEndpoint属性

@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的初始化
TokenEndpoint的初始化发生在配置类AuthorizationServerEndpointsConfiguration中,他是由注解@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);//直接注入
        tokenEndpoint.setProviderExceptionHandler(exceptionTranslator());
        tokenEndpoint.setTokenGranter(tokenGranter());
        tokenEndpoint.setOAuth2RequestFactory(oauth2RequestFactory());
        tokenEndpoint.setOAuth2RequestValidator(oauth2RequestValidator());
        tokenEndpoint.setAllowedRequestMethods(allowedTokenEndpointRequestMethods());
        return tokenEndpoint;
    }


1.3 postAccessToken
因为获取token的url是/oauth/token,所以他会进入下面的代码

@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 {
        
        //接口必须进行了身份认证
        if (!(principal instanceof Authentication)) {throw new InsufficientAuthenticationException("");}
        
        //从请求头中取出clientId
        String clientId = getClientId(principal);
        //通过ClientDetailsService读取数据库端点信息
        ClientDetails authenticatedClient = getClientDetailsService().loadClientByClientId(clientId);
        //封装端点信息+请求其他参数
        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)) {
            // 在授权步骤中请求或确定了范围
            if (!tokenRequest.getScope().isEmpty()) {
                tokenRequest.setScope(Collections.<String> emptySet());
            }
        }
 
        if (isRefreshTokenRequest(parameters)) {
            // 刷新令牌有其自己的默认作用域,因此我们应该忽略工厂在此处添加的任何标记。
            tokenRequest.setScope(OAuth2Utils.parseParameterList(parameters.get(OAuth2Utils.SCOPE)));
        }
        //核心方法:获取token,并把它装配到OAuth2AccessToken中
        OAuth2AccessToken token = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest);
        if (token == null) {
            throw new UnsupportedGrantTypeException("Unsupported grant type: " + tokenRequest.getGrantType());
        }
        return getResponse(token);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值