Spring Boot - 无法通过 Zuul 代理获得 Keycloak 授权 api 的响应

Posted

技术标签:

【中文标题】Spring Boot - 无法通过 Zuul 代理获得 Keycloak 授权 api 的响应【英文标题】:Spring Boot - Unable to get response of Keycloak authorized api via Zuul proxy 【发布时间】:2019-12-26 22:17:12 【问题描述】:

我为我的应用程序使用 Spring Boot 微服务和 docker。我已经通过 Zuul 代理公开了所有端点。而且我还使用 keycloak 来保护我的 api 端点。我在application.properties 文件中配置如下所示。目前我无法获得使用keycloak.securityConstraints授权的微服务api的响应。

请注意,我还将 docker0 的子网和网关更改为 169.254.0.1/24169.254.0.1。请找到我的应用程序的以下文件。

docker-compose.yml 不指定子网

version: "3"
services:
    eureka-naming-server:
        image: eureka-naming-server
        ports:
            - "8761:8761"
        container_name: eureka-naming-server
    zuul-proxy-service:
        image: zuul-proxy-service
        ports:
            - "8765:8765"
        links:
            - eureka-naming-server
        container_name: zuul-proxy-service
    user-service:
        image: user-service
        ports:
            - "8082:8082"
        links:
            - eureka-naming-server
        container_name: user-service
    keycloak:
        image: jboss/keycloak
        container_name: keycloak
        environment:
            KEYCLOAK_USER: user
            KEYCLOAK_PASSWORD: user_password
        ports:
            - 8080:8080

docker-compose.yml 指定默认子网

version: "3"
services:
    eureka-naming-server:
        image: eureka-naming-server
        ports:
            - "8761:8761"
        container_name: eureka-naming-server
    zuul-proxy-service:
        image: zuul-proxy-service
        ports:
            - "8765:8765"
        links:
            - eureka-naming-server
        container_name: zuul-proxy-service
    user-service:
        image: user-service
        ports:
            - "8082:8082"
        links:
            - eureka-naming-server
        container_name: user-service
    keycloak:
        image: jboss/keycloak
        container_name: keycloak
        environment:
            KEYCLOAK_USER: user
            KEYCLOAK_PASSWORD: user_password
        ports:
            - 8080:8080
networks:
    default:
        ipam:
            config:
                - subnet: "169.254.3.0/24"

application.yml 的 Zull 代理

server:
  port: 8765

eureka:
  client:
    serviceUrl:
      defaultZone: http://eureka-naming-server:8761/eureka/
  instance:
    prefer-ip-address: true
    metadataMap:
      instanceId: $vcap.application.instance_id:$spring.application.name:$spring.application.instance_id:$random.value
    instanceId: $vcap.application.instance_id:$spring.application.name:$spring.application.instance_id:$random.value

zuul:
  prefix: /api
  sensitive-headers:
  add-proxy-headers: false
  routes:
    user-service:
      path: /user/**
      service-id: USER-SERVICE

application.yml 的用户服务

spring.application.name=user-service
keycloak.realm=master
keycloak.resource=my-client
keycloak.auth-server-url=http://<ip>/auth
keycloak.public-client=true
keycloak.principal-attribute=preferred_username
keycloak.securityConstraints[0].authRoles[0]=admin
keycloak.securityConstraints[0].securityCollections[0].patterns[0]=/change-password

这是我的问题

1) 当我不使用 zuul 代理(即 http//:8082/change-password)时,我可以使用有效的 keycloak 令牌成功获得响应。但是当使用 http//:8765/api/user/change-passworddocker-compose.yml 指定默认子网时,我无法得到响应。 p>

对于有效令牌,我总是得到以下响应标头,状态为 200。

 cache-control: private 
 date: Wed, 21 Aug 2019 11:02:02 GMT 
 expires: Thu, 01 Jan 1970 00:00:00 GMT 
 transfer-encoding: chunked

并在用户服务日志中创建以下日志。

2019-08-21 03:18:26.191  WARN [-,,,] 1 --- [nio-8087-exec-2] o.k.adapters.RequestAuthenticator        : SSL is required to authenticate. Remote address 169.254.0.4 is secure: false, SSL required for: EXTERNAL .

但是,当我使用无效令牌时,我收到 401 错误(如预期的那样)。

我需要为这个问题使用路由过滤器吗???

任何帮助将不胜感激!

【问题讨论】:

【参考方案1】:

我在使用反向代理和代理背后的微服务时也遇到了这个问题,这些微服务具有 keyloak 集成。错误的原因是 keycloak 的某种安全实现检查反向代理提供的 X-Forward 标头。 documentation 对此进行了详细解释,但老实说,我并没有真正理解为什么需要它。因此,摆脱此错误的简单解决方案是简单地丢弃 X-Forward 标头,这会使请求看起来像内部请求。

在祖尔中:

zuul:
  add-proxy-headers: false

在 Spring Cloud 网关中:

spring:
  cloud:
    gateway:
      x-forwarded:
        port-enabled: false
        host-enabled: false
        proto-enabled: false
        port-append: false
        host-append: false
        proto-append: false
        enabled: false

在反向代理后面的每个微服务上设置keycloak.ssl-required 可能也可以工作,但我没有尝试。我更喜欢只将配置放在一个地方。

【讨论】:

【参考方案2】:

似乎所有外部请求都需要 SSL。这可以设置,例如通过Realm Settings -&gt; Login -&gt; Require SSL (https://www.keycloak.org/docs/5.0/server_admin/index.html#_ssl_modes) 中的管理控制台。 出于测试目的,您可以尝试将其设置为None。永远不要在生产系统上这样做。

可以为客户端做同样的事情(在用户服务的application.yml):

keycloak.ssl-required = none

(https://www.keycloak.org/docs/latest/securing_apps/index.html#_java_adapter_config)

【讨论】:

感谢您的及时回复。通过管理控制台设置无效。我目前正在使用 keycloak 5.0 版。你能解释一下你最后的建议吗? 您是否收到同样的错误?这也应该适用于版本 5 - 我更新了我的答案。 PROXY_ADDRESS_FORWARDING 设置为true 后,我收到Failed to fetch 错误。此外,我将 (169.254.3.6:8082/change-password) 作为 Request URL 招摇。 169.254.3.6 是从 docker-compose 创建的默认网络的 ip4 地址 好的,抱歉我弄错了。您的 Keycloak 不在代理后面吗?那么如果将 Require SSL 设置为 None 会发生什么?还有其他错误吗? 没有。我得到同样的错误。我上面已经提到了。

以上是关于Spring Boot - 无法通过 Zuul 代理获得 Keycloak 授权 api 的响应的主要内容,如果未能解决你的问题,请参考以下文章

Dockerized Spring boot 和 Zuul

在 Spring Boot 中使用 netflix zuul 面临微服务问题

Zuul url映射与spring boot,Eureka

spring boot + netflix zuul app给java.lang.ClassNotFoundException:com.netflix.zuul.monitoring.CounterF

Spring Boot 微服务 com.netflix.zuul.exception.ZuulException:转发错误

使用带有spring boot和eureka的@EnableZuulProxy闪烁Zuul TimeoutExceptions