在同时使用@ResourceServer和@ EnableOauth2Sso

时间:2017-01-26 03:50:42

标签: spring spring-boot spring-security

在我当前的项目中,我有一个应用程序,其中有一个小图形部分,用户使用SSO进行身份验证,以及一部分纯API,用户使用授权标头进行身份验证。

例如:

    使用SSO访问
  • /ping-other-service
  • /api/ping-other-service使用持票人令牌
  • 进行访问

作为所有云原生,我们的应用与使用JWT令牌(UAA)使用相同SSO提供商的其他服务进行通信,因此我认为自according to the documentation以来我们一直使用OAuth2RestTemplate它可以神奇地插入身份验证凭据。它确实对使用SSO进行身份验证的所有端点执行此操作。但是,当我们使用通过承载令牌进行修改的端点时,它不会填充其余模板。

我的理解from the documentation@EnableOAuth2Client只会从SSO登录中提取令牌,而不是auth标头?

我看到了什么

请求失败及其作用:

  1. curl -H "Authorization: Bearer <token>" http://localhost/api/ping-other-service
  2. 内部使用restTemplate来调用响应401的http://some-other-service/ping
  3. 成功的请求及其作用:

    1. Chrome http://localhost/ping-other-service
    2. 在内部使用restTemplate来调用响应200
    3. http://some-other-service/ping

      我们如何解决这个问题

      为了解决这个问题,我最终创建了以下怪物,如果它不能从授权标题中获取,它将从OAuth2ClientContext中提取令牌。

          @PostMapping(path = "/ping-other-service")
          public ResponseEntity ping(@PathVariable String caseId, HttpServletRequest request, RestTemplate restTemplate) {
              try {
                  restTemplate.postForEntity(adapterUrl + "/webhook/ping", getRequest(request), Map.class);
              } catch (HttpClientErrorException e) {
                  e.printStackTrace();
                  return new ResponseEntity(HttpStatus.SERVICE_UNAVAILABLE);
              }
      
              return new ResponseEntity(HttpStatus.OK);
          }
      
          private HttpEntity<?> getRequest(HttpServletRequest request) {
              HttpHeaders headers = new HttpHeaders();
              headers.set("Authorization", "Bearer " + getRequestToken(request));
              return new HttpEntity<>(null, headers);
          }
      
          private String getRequestToken(HttpServletRequest request) {
              Authentication token = new BearerTokenExtractor().extract(request);
              if (token != null) {
                  return (String) token.getPrincipal();
              } else {
                  OAuth2AccessToken accessToken = oAuth2ClientContext.getAccessToken();
      
                  if (accessToken != null) {
                      return accessToken.getValue();
                  }
              }
      
              throw new ResourceNotFound("No valid access token found");
          }
      

3 个答案:

答案 0 :(得分:1)

let modified = text.replacingOccurrences(of: "\\s", with: " ", options: .regularExpression) 资源中有一个传入令牌,但由于您使用的是JWT,资源服务器可以在不调用auth服务器的情况下进行身份验证,因此没有/api/**只是等待等待您可以在令牌中继中重用上下文(如果您使用OAuth2RestTemplate则会有一个)。您可以非常轻松地创建一个,并将传入的令牌拉出UserInfoTokenServices。例如:

SecurityContext

您可以将该方法转换为 @Autowired private OAuth2ProtectedResourceDetails resource; private OAuth2RestTemplate tokenRelayTemplate(Principal principal) { OAuth2Authentication authentication = (OAuth2Authentication) principal; OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) authentication.getDetails(); details.getTokenValue(); OAuth2ClientContext context = new DefaultOAuth2ClientContext(new DefaultOAuth2AccessToken(details.getTokenValue())); return new OAuth2RestTemplate(resource, context); } (在@Bean中)并根据需要为模板注入@Scope("request")

Spring Cloud Security中有一些自动配置和实用程序类来帮助处理这种模式,例如:https://github.com/spring-cloud/spring-cloud-security/blob/master/spring-cloud-security/src/main/java/org/springframework/cloud/security/oauth2/client/AccessTokenContextRelay.java

答案 1 :(得分:0)

我在开发Spring资源服务器时遇到了这个问题,我需要将OAuth2令牌从请求传递给restTemplate以调用下游资源服务器。两个资源服务器都使用相同的auth服务器,我发现Dave的链接很有帮助,但我不得不挖掘一下以了解如何实现它。我最终找到了文档here,结果显示实现非常简单。我正在使用@EnableOAuth2Client,因此我必须使用注入的restTemplate创建OAuth2ClientContext bean并创建适当的资源详细信息。就我而言,它是ClientCredentialsResourceDetails。感谢Dave的所有伟大作品!

@Bean 
public OAuth2RestOperations restTemplate (OAuth2ClientContext context) {
    ClientCredentialsResourceDetails details = new ClientCredentialsResourceDetails();
    // Configure the details here
    return new OAuth2RestTemplate(details, context)
}

答案 2 :(得分:0)

@Dave Syer 我的UAA服务还是oauth2客户端,它需要中继来自Zuul的JWT令牌。通过以下方式配置oauth2客户端时

@Configuration
@EnableOAuth2Client
@RibbonClient(name = "downstream")
public class OAuthClientConfiguration {

    @Bean
    public OAuth2RestTemplate restTemplate(OAuth2ProtectedResourceDetails resource, OAuth2ClientContext context) {
        return new OAuth2RestTemplate(resource, context);
    }
}

我确实从下游服务获得401响应,因为我的访问令牌的有效性非常短,并且AccessTokenContextRelay不会更新传入的访问令牌(Zuul确实通过刷新令牌来更新过期的访问令牌)。 / p>

OAuth2RestTemplate#getAccessToken将永远不会获取新的访问令牌,因为isExpired存储的访问令牌上的AccessTokenContextRelay会丢弃有效性和刷新令牌信息。

如何解决?