【问题标题】:Refresh OAuth Token in Spring boot OAuth2RestOperations在 Spring Boot OAuth2RestOperations 中刷新 OAuth 令牌
【发布时间】:2020-02-17 03:03:44
【问题描述】:

我正在使用 Spring Boot Cloud OAuth 客户端连接 Salesforce restapi。但是我收到Session expired or invalid 错误。无论如何刷新令牌我假设Spring Boot会在后台自动处理这个问题,但似乎情况并非如此。这是相关代码。

@Configuration
public class SalesforceConfiguration {

    @Value("${salesforce.tokenUrl}")
    private String tokenUrl;

    @Value("${salesforce.clientId}")
    private String clientId;

    @Value("${salesforce.clientSecret}")
    private String clientSecret;

    @Value("${salesforce.username}")
    private String username;

    @Value("${salesforce.password}")
    private String password;

    @Bean
    protected OAuth2ProtectedResourceDetails resource() {

        ResourceOwnerPasswordResourceDetails resource = new ResourceOwnerPasswordResourceDetails();

        resource.setAccessTokenUri(tokenUrl);
        resource.setClientId(clientId);
        resource.setClientSecret(clientSecret);
        resource.setClientAuthenticationScheme(AuthenticationScheme.form);
        resource.setUsername(username);
        resource.setPassword(password);

        return resource;
    }

    @Bean
    public OAuth2RestOperations restTemplate() {

        OAuth2RestTemplate operations = new OAuth2RestTemplate(resource(), new DefaultOAuth2ClientContext(new DefaultAccessTokenRequest()));
        operations.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
        operations.getMessageConverters().add(new StringHttpMessageConverter());

        return operations;
    }
}

这就是我在服务中使用它的方式。

@Component
public class QueryExecutor extends AbstractExecutor implements SalesforceExecutor {

    private OAuth2RestOperations restOperations;

    public QueryExecutor(OAuth2RestOperations restOperations) {

        this.restOperations = restOperations;
    }

    @Override
    public Response process(Request request) throws Exception {

        JsonNode jsonNode = restOperations.getForObject(buildUrl(request), JsonNode.class);

        return new Response<>(ResponseCode.SUCCESS_GET.getCode(), jsonNode, request.getResponseHandler());
    }

    private String buildUrl(Request request) {

        return new StringBuilder().append(getServiceUrl(restOperations))
                                  .append("/services/data/v41.0/query/?q=")
                                  .append(request.getPayload().get("query"))
                                  .toString();
    }
}

如果我收到会话过期错误,是否可以使用这种方法无缝刷新令牌?

【问题讨论】:

    标签: spring-boot salesforce spring-cloud spring-security-oauth2 spring-oauth2


    【解决方案1】:

    好吧,经过几天的调试,我想我找到了这个问题的解决方案。这就是我能够解决它的方法。我将解决方案放在这里,以便其他人可以从中受益。

    @Component
    public class QueryExecutor implements SalesforceExecutor {
    
        private OAuth2RestOperations restOperations;
    
        public QueryExecutor(OAuth2RestOperations restOperations) {
    
            this.restOperations = restOperations;
        }
    
        @Override
        public Response process(Request request) throws Exception {
    
            try {
    
                JsonNode jsonNode = restOperations.getForObject(buildUrl(request), JsonNode.class);
    
                return new Response<>(ResponseCode.SUCCESS_GET.getCode(), jsonNode, request.getResponseHandler());
    
            } catch (HttpClientErrorException | HttpServerErrorException e) {
    
                if (HttpStatus.UNAUTHORIZED.value() == e.getStatusCode().value()) {
    
                    restOperations.getOAuth2ClientContext().setAccessToken(this.getRenewedToken(restOperations.getResource()));
                }
    
                // retry again with renewed token
            }
        }
    
        private String buildUrl(Request request) {
    
            return "someurl";
        }
    
        private OAuth2AccessToken getRenewedToken(OAuth2ProtectedResourceDetails resource) {
    
            OAuth2RestTemplate oAuth2RestTemplate = new OAuth2RestTemplate(resource, new DefaultOAuth2ClientContext(new DefaultAccessTokenRequest()));
    
            return oAuth2RestTemplate.getOAuth2ClientContext().getAccessToken();
        }
    }
    
    

    就是这样。

    【讨论】:

      【解决方案2】:

      使用 Spring Boot,您应该不需要整个 SalesforceConfiguration 配置类。

      您可以使用以下依赖项:

      <dependency>
          <groupId>org.springframework.security.oauth.boot</groupId>
          <artifactId>spring-security-oauth2-autoconfigure</artifactId>
           <version>${look-for-the-latest}</version>
      </dependency>
      
      <dependency>
          <groupId>org.springframework.security</groupId>
          <artifactId>spring-security-oauth2-client</artifactId>
      </dependency>
      

      将配置属性添加到您的application.yml

      security:
        oauth2:
          client:
            username: the-username
            password: the-password
            client-id: the-client-id
            client-secret: the-client-secret
            grant-type: password,refresh_token
            scope: read
            access-token-uri: http://sales-force-domain/oauth/token
      

      然后你可以像这样定义你的OAuth2RestTemplate

          @Bean
          public OAuth2RestTemplate oAuth2RestTemplate(final OAuth2ProtectedResourceDetails details) {
              return new OAuth2RestTemplate(details);
          }
      

      要使用它,只需按照您已经在做的方式,将OAuth2RestTemplate 注入QueryExecutor。一旦您在application.yml 中将刷新令牌定义为grant-type,Spring 就会处理刷新令牌。

      In this repo,我有这个配置的工作版本,请耐心等待,因为它还演示了如何手动创建这个配置。

      【讨论】:

      • 谢谢,我会试试这个。但是是否会处理令牌刷新/会话超时?
      • 这就是使用 Spring 的全部意义 :) 它确实会为您解决问题,只需正确设置即可。如果您确实将grant_type 设置为refresh_token 以及您需要的类型,它会成功
      • 如果它对您有用,并且您可以将我的答案标记为正确答案,我将不胜感激。
      • 遗憾的是,我收到了Unable to obtain a new access token for resource 'null'. The provider manager is not configured to support it.,这是我以前没有收到的。
      • 你能分享一些代码吗?公共回购将是最好的
      猜你喜欢
      • 2017-10-27
      • 2015-06-02
      • 2018-06-17
      • 1970-01-01
      • 2020-02-08
      • 2020-05-05
      • 2020-07-17
      • 2017-02-08
      • 2018-09-27
      相关资源
      最近更新 更多