You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Traefik、Keycloak与WebApp集成故障:无法获取OpenID配置

问题描述

通过Docker Compose在服务器部署Traefik、Keycloak与WebApp服务,预期流程为:WebApp基于OpenIdConnect实现授权,访问其域名时会调用Keycloak容器展示授权表单,登录成功后Keycloak重定向回WebApp并展示内容。

当前异常:访问WebApp域名时,日志报错Unable to obtain configuration from: 'https://example.com/realms/Investigacion/.well-known/openid-configuration',但直接访问该链接可正常显示Realm的配置信息,怀疑问题出在Traefik的请求处理逻辑上。

Docker Compose配置

services:

  reverse-proxy:
    image: traefik:v3.1
    command:
      - "--log.level=DEBUG"
      - "--providers.docker"
      - "--providers.docker.exposedbydefault=false"
      - "--certificatesresolvers.myresolver.acme.tlschallenge=true"
      - "--certificatesresolvers.myresolver.acme.email=email@domain.cloud"
      - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme-v1.json"
      - "--entrypoints.web.address=:8080"
      - "--entrypoints.websecure.address=:443"
      - "--entrypoints.websecure.asDefault=true"
      - "--entrypoints.web.http.redirections.entrypoint.to=websecure"
      - "--entrypoints.web.http.redirections.entrypoint.scheme=https"
    ports:
      - "8080:8080"
      - "443:443"
    volumes:
      - letsencrypt:/letsencrypt
      - /var/run/docker.sock:/var/run/docker.sock
    networks:
      - webnet

  kcdb:
    container_name: kcdb
    image: postgres:16.2
    restart: unless-stopped
    environment:
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - POSTGRES_DB=${POSTGRES_DB}
    expose:
      - 5432
    volumes:
      - pgdata:/var/lib/postgresql/data
    networks:
      - webnet

  keycloak:
    image: quay.io/keycloak/keycloak:26.0.7
    command: start
    environment:
      KC_HOSTNAME: keycloak.thesispath.cloud
      PROXY_ADDRESS_FORWARDING: true
      KC_HOSTNAME_PORT: 8088
      KC_HOSTNAME_STRICT: false
      KC_PROXY_HEADERS: 'xforwarded'
      KC_HTTP_ENABLED: true
      KEYCLOAK_LOGLEVEL: DEBUG
      KC_HEALTH_ENABLED: true
      KEYCLOAK_ADMIN: ${KEYCLOAK_ADMIN}
      KEYCLOAK_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD}
      KC_DB: postgres
      KC_DB_URL: jdbc:postgresql://kcdb/${POSTGRES_DB}
      KC_DB_USERNAME: ${POSTGRES_USER}
      KC_DB_PASSWORD: ${POSTGRES_PASSWORD}
    restart: always
    ports:
      - "8088:8088"
    depends_on:
      - kcdb
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.keycloak.rule=Host(`keycloak.domain.cloud`)"
      - "traefik.http.routers.keycloak.entrypoints=websecure"
      - "traefik.http.routers.keycloak.tls.certresolver=myresolver"
    networks:
      - webnet

  webApp:
    image: webApp:v6.1
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.webApp.rule=Host(`webApp.domain.cloud`)"
      - "traefik.http.routers.webApp.entrypoints=websecure"
      - "traefik.http.routers.webApp.tls.certresolver=myresolver"
    networks:
      - webnet
      
networks:
  webnet:
    driver: bridge
volumes:
  pgdata:
  letsencrypt:

Program.cs中的OpenIdConnect配置

.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
    options.Authority = builder.Configuration["Authentication:OpenId:Authority"];
    options.ClientId = builder.Configuration["Authentication:OpenId:ClientId"];
    options.ClientSecret = builder.Configuration["Authentication:OpenId:ClientSecret"];
    options.ResponseType = "code";
    options.SaveTokens = true;
    options.RequireHttpsMetadata = bool.Parse(builder.Configuration["Authentication:OpenId:Metadata"]);
    if (options.RequireHttpsMetadata)
    {
        options.MetadataAddress = builder.Configuration["Authentication:OpenId:MetaAddress"];
    }
    options.Scope.Add("openid");
    options.CallbackPath = "/login-callback";
    options.SignedOutCallbackPath = "/logout-callback";
    options.TokenValidationParameters = new TokenValidationParameters
    {
        NameClaimType = "preferred_username",
        RoleClaimType = "roles"
    };

})

appsettings.json配置

"OpenId": {
      "ClientId": "InvestigacionClient",
      "ClientSecret": "ClientSecret",
      "Authority": "https://example.com/realms/Investigacion",
      "MetaAddress": "https://example.com/realms/Investigacion/.well-known/openid-configuration",
      "Metadata": true
    }

错误日志

fail: Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[1]
      An unhandled exception has occurred while executing the request.
      System.InvalidOperationException: IDX20803: Unable to obtain configuration from: 'https://example.com/realms/Investigacion/.well-known/openid-configuration'. Will retry at '12/16/2024 22:34:40 +00:00'. Exception: 'System.IO.IOException: IDX20804: Unable to retrieve document from: 'https://example.com/realms/Investigacion/.well-known/openid-configuration'.
       ---> System.Threading.Tasks.TaskCanceledException: The request was canceled due to the configured HttpClient.Timeout of 60 seconds elapsing.
       ---> System.TimeoutException: A task was canceled.
 ---> System.Threading.Tasks.TaskCanceledException: A task was canceled.
   at System.Threading.Tasks.TaskCompletionSourceWithCancellation`1.WaitWithCancellationAsync(CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
问题分析与解决方案

从错误日志看,WebApp容器内部请求Keycloak的OIDC元数据地址超时,外部访问正常,核心原因是容器内部网络路由或配置冲突,以下是针对性修复方案:

1. 修正Keycloak端口与代理配置

Keycloak默认监听8080端口,但当前配置映射了8088端口却未指定内部监听端口,同时代理配置错误导致Traefik转发请求无法到达Keycloak:

keycloak:
  environment:
    # 指定内部监听端口
    KC_HTTP_PORT: 8088
    # 移除错误的端口配置,使用edge代理适配Traefik
    KC_PROXY: edge
    # 关闭严格HTTPS检查,适配内部HTTP访问
    KC_HOSTNAME_STRICT_HTTPS: false
    # 删除KC_HOSTNAME_PORT配置,由Traefik处理端口转发
  ports:
    - "8088:8088"

2. 解决WebApp内部DNS解析超时问题

WebApp容器内部无法正确解析Keycloak的外部域名,导致请求超时,可通过两种方式修复:

  • 方案一:添加容器hosts映射
    让WebApp直接将Keycloak域名解析到Traefik容器IP(替换TRAEFIK_IP为宿主机或Traefik容器的实际IP):
webApp:
  extra_hosts:
    - "example.com:TRAEFIK_IP"
  • 方案二:使用内部服务名访问Keycloak
    修改appsettings.json,直接通过容器名访问Keycloak内部服务:
"OpenId": {
  "Authority": "http://keycloak:8088/realms/Investigacion",
  "MetaAddress": "http://keycloak:8088/realms/Investigacion/.well-known/openid-configuration",
  "Metadata": false
}

3. 修正Traefik ACME协议版本

Traefik v3.1使用ACME v2协议,当前存储路径为v1格式会导致证书异常:

reverse-proxy:
  command:
    - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme-v2.json"

内容的提问来源于stack exchange,提问作者Martin Solari Vargas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 12:00:56