如何使用Spring Cloud Security实现OAuth2的“令牌交换”

16

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

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

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

我猜想,参考文档中的“Token Exchange”是指实现OAuth2的此扩展,该扩展在这个规范中有所解释,这正是我需要的:https://datatracker.ietf.org/doc/html/draft-ietf-oauth-token-exchange-03

正如我所说,我懂得如何使用SSO和Token Relay,但我无法找到关于如何在参考文档中实现“Token Exchange”的更进一步的说明。我也没有找到实现示例。

有人知道在哪里可以找到更多信息或示例吗?
非常感谢!


同意。在所有微服务中重复使用client_id似乎是错误的。最糟糕的部分(在我看来)是它阻止了其他客户端使用微服务。假设您有另一个具有自己client_id的sso客户端...那么您就无法使用任何现有的微服务?希望这得到解决。看起来已经完成/合并了令牌交换的一些工作,但还没有完全完成https://github.com/spring-projects/spring-security-oauth/pull/957 - sdoxsee
乍一看,我同意你的观点。但从客户的角度来看,他们将您的API网关视为一个奇点。从他们的角度来看,只有一个API。您在其后面拥有多个服务的事实是实现细节,不一定是您想要向客户展示的内容。如果您决定将一个服务拆分为两个服务,会发生什么情况?您是否需要让每个人重新发放授予新资源ID的令牌? - Ryan J. McDonough
2个回答

2

我想这可能是你可以尝试的事情。

在我的项目中,我们也使用OAuth2、Eureka、Ribbon来实现微服务之间的通信。为了将Ribbon与OAuth2结合使用,我们采用了不同的方法。

首先,我们保持了restTemplate不变。

  @LoadBalanced
  @Bean
  public RestTemplate restTemplate() {

然而,我们创建了FeignClientIntercepter实现RequestIntercepter,通过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()));
      }
    }
  }

2
我很好奇为什么需要通过“交换”令牌才能从微服务A调用微服务B,并且为什么中继不足够?通过交换令牌来进行服务间请求,您想实现什么目的?
我们的设置与此 Nordic APIs 文章非常相似。简而言之,外部调用者使用不透明令牌,但是一旦请求经过我们的网关,每个微服务都会获得相同令牌的 JWT 表示形式。我们必须实现自定义端点以执行不透明到 JWT 的交换。当服务需要彼此交互时, A 需要调用 B 时,我们不会交换令牌,我们只是传递令牌。无论是 RestTemplate 还是 Feign 客户端都将自动将令牌从 A 转发到 B,因此上下文不会丢失。
现在,如果我们想控制访问权限,JWT 可以指定一组受众值,或者我们可以通过范围强制访问控制。根据用例,我们实际上正在同时执行这两种方法。
交换令牌并不是一项廉价的操作,事实上,在规模上它非常昂贵,您应该确保您的授权服务可以处理这种类型的工作负载。最后,IETF 令牌交换仍然处于草案状态,并且在其演变中发生了很大变化,因此我不希望在规范接近最终化之前获得太多实施建议。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接