java - Spring Cloud Gateway + Spring安全资源服务器

标签 java spring spring-security oauth-2.0 spring-cloud-gateway

我真的不会把它放在这里,但我真的很困惑, 我想实现以下目标。

我正在运行

  • Java 14
  • Spring Cloud Gateway 版本:Hoxton.SR3
  • Spring Boot 版本:2.2.5.RELEASE

现在我想将安全性集成到我的网关和所有下游微服务中。最终,我决定使用 Firebase 作为身份提供商 (IDP)。我的 Angular 应用程序将从 Firebase 获取 JWT token ,并将其在每个请求中发送到云网关。因此,网关将开始仅充当资源服务器,仅此而已。

这是我如何尝试的。 同时设置 Spring Cloud Gateway 充当资源服务器。 这里解释得很好Spring Security Docs .

这是我的配置

@EnableWebFluxSecurity
public class ResourceServerSecurityConfiguration {

  @Bean
  public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
    // @formatter:off
    http
        .authorizeExchange()
        .anyExchange().authenticated()
        .and()
        .oauth2ResourceServer()
        .jwt();
    return http.build();
    // @formatter:on
  }
}

和application.yml

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          jwk-set-uri: https://www.googleapis.com/service_accounts/v1/jwk/<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="6c1f090f191e0918030709022c1f151f180901420b1f091e1a050f090d0f0f03190218420f0301" rel="noreferrer noopener nofollow">[email protected]</a>
          issuer-uri: https://securetoken.google.com/{$app.name}

正如您在此 YAML 中看到的,我提供了 jwk-set-uri 和颁发者来验证传入的 token 。

至此,所有工作都已被接受。所有请求都必须在身份验证 header 中包含有效的 JWT。

下一步,

我希望我的网关使用 WebClient 并调用多个服务来聚合前端数据。

这是我尝试配置我的客户端的方法。

  @Bean
  @LoadBalanced
  public WebClient.Builder loadBalancedWebClientBuilder() {
    return WebClient.builder()
        .filter(new ServletBearerExchangeFilterFunction());
  }

如您所见,它使用 ServletBearerExchangeFilterFunction 这是我真正的问题所在。

我已经检查过,当 Spring 配置 oauth2ResourceServer 时,它使用 NoOpServerSecurityContextRepository。据我所知,到目前为止,这正是一个用于注册每个请求上下文的存储库。另外,我知道使用 NoOp 是有意义的,因为我们想要无状态。但是我不明白如何使 ServletBearerExchangeFilterFunction 正常工作并向下游传递我的 token 。

我现在花了很多时间试图找出正确的方法。

发现这个: Spring Boot 2 OIDC (OAuth2) client / resource server not propagating the access token in the WebClient

Github:https://github.com/spring-projects/spring-security/issues/7771

即使根据这一点,我尝试做的事情也应该是合法且可能的。不知道我哪里错了。

最佳答案

我想到了这一点,问题是 ReactiveSecurityContext 仅当您处于 react 流中且 ServletBearerExchangeFilterFunction 用于 Servlet 调用时才可用。

最终,我刚刚编写了自己的过滤器函数,该函数监听 ReactiveSecurity 上下文并设置 Authorization header 。在这里。

public class BearerExchangeFilterFunction implements ExchangeFilterFunction {

  @Override
  @NonNull
  public Mono<ClientResponse> filter(@NonNull ClientRequest request, ExchangeFunction next) {
    return ReactiveSecurityContextHolder.getContext()
        .map(c -> (c.getAuthentication().getCredentials()))
        .cast(AbstractOAuth2Token.class)
        .checkpoint()
        .map(token -> bearer(request, token))
        .defaultIfEmpty(request)
        .flatMap(next::exchange);
  }

  private ClientRequest bearer(ClientRequest request, AbstractOAuth2Token token) {
    return ClientRequest.from(request)
        .headers(headers -> headers.setBearerAuth(token.getTokenValue()))
        .build();
  }


}

关于java - Spring Cloud Gateway + Spring安全资源服务器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61511710/

相关文章:

html - Freemarker 中的 CSS spring.formInput

spring - 如何在 .antmatchers.access() 中使用常量

java - 删除文本文件中较短的字符串

java - 使用 SSL(自签名)证书通过 Spring 和 Hibernate 连接 MariaDB

java - 如何更改 fragment 文本?

spring - 从 Controller 重定向到项目外的不同 URL

java - 我可以将 3 种不同的身份验证方案放在同一个 spring 安全配置中吗?

java - 用于内部 REST 通信的 OAuth + spring security

java - 在另一个 Controller 中重用 Spring 服务 Controller 功能

java - 二叉最小堆的链表实现(操作遇到麻烦......)