14

我想知道是否有人有一个例子来了解如何使用 Spring Cloud Security(使用 OAuth2)实现“令牌交换”技术。

目前,我已经在使用 ZuulProxy 的微服务环境中实现了“令牌中继”技术来“中继”OAuth2 令牌并实现 SSO。这很好,但意味着每个微服务都使用相同的 clientId(在 ZuulProxy 设置中指定,因为 ZuulProxy 仅使用 authentication_code 授权类型和提供的 clientId 中继令牌)。但是,对于内部微服务调用,我想“交换”令牌。这意味着在某些情况下,ZuulProxy 中继的令牌不是我需要用来验证/授权微服务 A 作为微服务 B 的客户端的令牌。

Spring Cloud 参考文档目前说:“在 Spring Boot 和 Spring Security OAuth2 的基础上,我们可以快速创建实现单点登录、令牌中继和令牌交换等常见模式的系统。” ( http://cloud.spring.io/spring-cloud-security/spring-cloud-security.html )

我想参考文档中的“令牌交换”是指 OAuth2 扩展的实现,在本规范中进行了解释,这基本上是我需要的: https ://datatracker.ietf.org/doc/html/draft- ietf-oauth-token-exchange-03

正如我所说,我了解如何使用 SSO 和令牌中继,但我无法在参考文档中看到有关如何实现“令牌交换”的进一步说明。我也找不到实现示例。

有谁知道我在哪里可以找到更多信息或示例?

非常感谢!

4

2 回答 2

2

我很好奇为什么您需要“交换”令牌以从微服务 A 向微服务 B 进行调用,以及为什么中继还不够?您通过为服务间请求交换令牌来尝试实现什么?

我们的设置与此Nordic API 条目中描述的内容非常相似。简短的版本是外部调用者使用不透明的令牌,但是一旦请求通过我们的网关,每个微服务都会获得相同令牌的 JWT 表示。我们必须实现一个自定义端点来执行对 JWT 的不透明交换。当服务需要相互交互时,当 A 需要调用 B 时,我们不交换令牌,我们只是中继令牌。RestTemplate 或 Feign 客户端都会自动将令牌从 A 转发到 B。因此,上下文不会丢失。

现在,如果我们想控制访问,JWT 可以指定一组受众值,或者我们可以通过范围强制访问。我们实际上是根据用例将两者结合起来。

交换代币并不是一项便宜的操作,事实上它在规模上相当昂贵,并且应该真正考虑为什么需要为服务内通信进行代币交换。如果您的每个 API 请求都会导致服务 A 调用服务 B,并且您必须进行令牌交换,那么您将确保您的授权服务可以处理这种类型的工作负载。最后,IETF 令牌交换仍处于草案状态,并且在其演变过程中发生了相当大的变化,因此在规范接近最终确定之前,我不会对实施建议的方式抱有太大期望。

于 2017-01-23T01:35:03.427 回答
2

我认为这是你可以尝试的。

在我的项目中,我们还使用 OAuth2、Eureka、Ribbon 让微服务相互通信。为了将 Ribbon 与 OAuth2 一起使用,我们采用的方法有点不同。

首先,我们保持 restTemplate 不变。

  @LoadBalanced
  @Bean
  public RestTemplate restTemplate() {

但是,我们创建了实现 RequestIntercepter 的 FeignClientIntercepter,它在通过 restTemplate 发出请求时为 OAuth 设置授权令牌。

  @Component
  public class FeignClientInterceptor implements RequestInterceptor {

    private static final String AUTHORIZATION_HEADER = "Authorization";
    private static final String BEARER_TOKEN_TYPE = "Jwt";

    @Override
    public void apply(RequestTemplate template) {
      SecurityContext securityContext = SecurityContextHolder.getContext();
      Authentication authentication = securityContext.getAuthentication();

      if (authentication != null && authentication
          .getDetails() instanceof OAuth2AuthenticationDetails) {
        OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) authentication
          .getDetails();
        template.header(AUTHORIZATION_HEADER,
            String.format("%s %s", BEARER_TOKEN_TYPE, details.getTokenValue()));
      }
    }
  }
于 2018-10-02T10:17:16.730 回答