Spring Cloud Gateway + Spring Security 和多个 OAuth2 客户端

问题描述 投票:0回答:3

我将把 Spring Cloud Gateway 放在一些现有的 Web 应用程序前面,这些应用程序已经使用 Keycloak 作为其身份提供者,并且我想对网关内的传入请求进行身份验证。

目前,每个 Web 应用程序都已配置了正确的客户端 ID,并使用正确的值重定向到 Keycloak。

现在,网关必须执行授权代码流程,而不是每个应用程序,因此它必须提前知道哪个 client-id 对应哪个请求的 url。

所以,我正在研究如何实现它,但我仍然在这里没有任何适当的解决方案。有什么解决办法吗?这样做甚至是网关的责任吗?

spring-security oauth-2.0 spring-cloud-gateway
3个回答
1
投票

实际上,我找到了一个解决方案,但我不确定它是否是最好的。

 @Bean
    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
        http
                .authorizeExchange().pathMatchers("/actuator/**").permitAll().and()
                .authorizeExchange().anyExchange().authenticated().and().csrf().disable().oauth2Login()
                .and()
                .exceptionHandling().authenticationEntryPoint(createEntryPoints())
                .and()
                .oauth2ResourceServer().jwt()
                .jwtAuthenticationConverter(grantedAuthoritiesExtractor());
        return http.build();
    }

    public ServerAuthenticationEntryPoint createEntryPoints() {
        List<DelegateEntry> entryPoints = new ArrayList<>();
        entryPoints
                .add(new DelegateEntry(ServerWebExchangeMatchers.pathMatchers("/app1"),
                        new RedirectServerAuthenticationEntryPoint("/oauth2/authorization/client1")));
        //other clients will be added here
        DelegatingServerAuthenticationEntryPoint defaultEntryPoint = new DelegatingServerAuthenticationEntryPoint(
                entryPoints);
        defaultEntryPoint.setDefaultEntryPoint(new HttpStatusServerEntryPoint(HttpStatus.UNAUTHORIZED));
        return defaultEntryPoint;
    }

因此 client1 将用于 /app1 等等。 正如我之前所说,我不确定,可能有更好的解决方案。


0
投票

对于基于 Spring Boot 和 Spring Cloud Gateway 的网关,必要的步骤概述如下。

1。定义您的 OAuth2 客户端

首先您需要定义 OAuth2 客户端。最简单的方法是依靠自动配置(参见 ReactiveOAuth2ClientConfigurations)并将它们放入

application.yml
:

spring:
  security:
    oauth2:
      client:
        provider:
          keycloak:
            issuer-uri: ...
        registration:
          client-1:
            provider: keycloak
            client-id: ...
            client-secret: ...
          client-2:
            provider: keycloak
            client-id: ...
            client-secret: ...

2。配置TokenRelay过滤器

您需要确保 TokenRelay 过滤器 将用于匹配 OAuth2 客户端的令牌传递到您的后端服务。同样,这可以在

application.yml
中完成:

spring:
  cloud:
    gateway:
      routes:
      - id: route-client-1
        uri: ...
        predicates:
        - Path=/client1/**
        filters:
        - TokenRelay=client-1
      - id: route-client-2
        uri: ...
        predicates:
          - Path=/client2/**
        filters:
          - TokenRelay=client-2

当与之前的代码片段合并时,请确保有单个根元素

spring

3.定义单独的

SecurityWebFilterChain
s

最后您需要定义单独的安全 Web 过滤器链。最大的原因是定义初始化 OAuth2 流的不同端点。因为否则 Spring Security 会呈现一个 HTML 页面,用户需要在其中显式选择正确的客户端注册。

    @Order(1)
    @Bean
    public SecurityWebFilterChain springSecurityFilterChainClient2(
        ServerHttpSecurity http
    ) {
        http.securityMatcher(
                new OrServerWebExchangeMatcher(
                    new PathPatternParserServerWebExchangeMatcher("/client2/**"),
                    new PathPatternParserServerWebExchangeMatcher("/oauth2/authorization/client-2"),
                    new PathPatternParserServerWebExchangeMatcher("/login/oauth2/code/client-2")
                )
            )
            .authorizeExchange(
                authorizeExchangeSpec ->
                    authorizeExchangeSpec.anyExchange().authenticated()
            )
            .exceptionHandling(
                exceptionHandlingSpec ->
                    exceptionHandlingSpec.authenticationEntryPoint(new RedirectServerAuthenticationEntryPoint("/oauth2/authorization/client-2"))
            )
            .oauth2Login(Customizer.withDefaults());
        return http.build();
    }

    @Order(2)
    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(
        ServerHttpSecurity http
    ) {
        http
            .securityMatcher(
                new OrServerWebExchangeMatcher(
                    new PathPatternParserServerWebExchangeMatcher("/client1/**"),
                    new PathPatternParserServerWebExchangeMatcher("/oauth2/authorization/client-1"),
                    new PathPatternParserServerWebExchangeMatcher("/login/oauth2/code/client-1")
                )
            )
            .authorizeExchange(
                authorizeExchangeSpec ->
                    authorizeExchangeSpec.anyExchange().authenticated()
            )
            .exceptionHandling(
                exceptionHandlingSpec ->
                    exceptionHandlingSpec.authenticationEntryPoint(new RedirectServerAuthenticationEntryPoint("/oauth2/authorization/client-1"))
            )
            .oauth2Login(Customizer.withDefaults());
        return http.build();
    }

-1
投票

你可以看看这个答案:

如何创建Spring Cloud网关过滤器来添加客户端凭据访问令牌?

为了支持不同的 client-id(secrets、token-uris 等),您可以在 spring.security.oauth2.client .registration 部分定义多个配置,并在 Oauth2ClientGatewayFilter 中使 clientid 动态化班级:

String clientId = ...
OAuth2AuthorizeRequest oAuth2AuthorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId(clientId)
                        .principal("myPrincipal").build();
© www.soinside.com 2019 - 2024. All rights reserved.