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

自托管KeyCloak与Ocelot网关集成时出现IDX10500签名验证失败错误

问题:KeyCloak + Ocelot API网关JWT签名验证失败(IDX10500)

在Docker部署的.NET Ocelot网关集成自托管KeyCloak时,能正常获取JWT令牌,但访问需要认证的/api/weatherforecast路由时,出现签名验证失败错误:IDX10500: Signature validation failed. No security keys were provided to validate the signature。容器间通信正常,本地浏览器可正常获取KeyCloak的OIDC配置。

相关配置

1. Program.cs 核心代码

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using Ocelot.DependencyInjection;
using Ocelot.Middleware;

var builder = WebApplication.CreateBuilder(args);

// 添加Ocelot配置
builder.Configuration.AddJsonFile("ocelot.json", optional: false, reloadOnChange: true);

// 注册Ocelot服务
builder.Services.AddOcelot(builder.Configuration);
builder.Services.AddHttpClient();

// Keycloak认证配置
builder.Services
    .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer("KeyCloak", options =>
    {
        options.Authority = "http://localhost:5002/realms/test-realm";
        options.Audience = "api-gw";
        options.MetadataAddress = "http://keycloak:5002/realms/test-realm/.well-known/openid-configuration";
        options.RequireHttpsMetadata = false;
        
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidIssuer = "http://localhost:5002/realms/test-realm",
            ValidateAudience = true,
            ValidAudience = "api-gw",
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ClockSkew = TimeSpan.Zero
        };
    
        options.Events = new JwtBearerEvents
        {
            OnTokenValidated = context =>
            {
                Console.WriteLine("Token Validated.");
                return Task.CompletedTask;
            },
            OnAuthenticationFailed = context => 
            { 
                Console.WriteLine($"Token Validation Failed: {context.Exception.Message}");
                return Task.CompletedTask;
            }
        };
    });

builder.Services.AddAuthorization();

var app = builder.Build();

app.UseAuthentication();
app.UseAuthorization();
app.UseHttpsRedirection();

app.UseOcelot().Wait();
app.Run();

2. Ocelot.json 路由配置

{
  "Routes": [
    {
      "DownstreamPathTemplate": "/login",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "auth-service",
          "Port": 8080
        }
      ],
      "UpstreamPathTemplate": "/login",
      "UpstreamHttpMethod": ["Post"]
    },
    {
      "DownstreamPathTemplate": "/todos/{id}",
      "DownstreamScheme": "https",
      "DownstreamHostAndPorts": [
        {
          "Host": "jsonplaceholder.typicode.com",
          "Port": 443
        }
      ],
      "UpstreamPathTemplate": "/api/todos/{id}",
      "UpstreamHttpMethod": ["Get"]
    },
    {
      "DownstreamPathTemplate": "/weatherforecast",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "temp-service",
          "Port": 8080
        }
      ],
      "UpstreamPathTemplate": "/api/weatherforecast",
      "UpstreamHttpMethod": ["Get"],
      "AuthenticationOptions": {
        "AuthenticationProviderKey": "KeyCloak",
        "AllowedScopes": []
      }
    }
  ],
  "GlobalConfiguration": {
    "BaseUrl": "https://localhost:5000"
  }
}

3. 错误日志

info: Ocelot.Authentication.Middleware.AuthenticationMiddleware[0]
2024-12-16 20:44:49       requestId: 0HN8U187GSHNG:00000003, previousRequestId: No PreviousRequestId, message: 'The path '/api/weatherforecast' is an authenticated route! AuthenticationMiddleware checking if client is authenticated...'
2024-12-16 20:44:50 Token Validation Failed: IDX10500: Signature validation failed. No security keys were provided to validate the signature.
2024-12-16 20:44:50 warn: Ocelot.Authentication.Middleware.AuthenticationMiddleware[0]
2024-12-16 20:44:50       requestId: 0HN8U187GSHNG:00000003, previousRequestId: No PreviousRequestId, message: 'Client has NOT been authenticated for path '/api/weatherforecast' and pipeline error set. Request for authenticated route '/api/weatherforecast' was unauthenticated;'
2024-12-16 20:44:50 warn: Ocelot.Responder.Middleware.ResponderMiddleware[0]
2024-12-16 20:44:50       requestId: 0HN8U187GSHNG:00000003, previousRequestId: No PreviousRequestId, message: 'Error Code: UnauthenticatedError Message: Request for authenticated route '/api/weatherforecast' was unauthenticated errors found in ResponderMiddleware. Setting error response for request path:/api/weatherforecast, request method: GET'

解决方案

1. 避免手动覆盖TokenValidationParameters实例

当你手动创建new TokenValidationParameters()时,会完全替换JwtBearer中间件从KeyCloak Metadata自动加载的配置(包括签名验证密钥),导致没有可用密钥验证签名。正确的做法是修改现有参数,而非新建实例:

.AddJwtBearer("KeyCloak", options =>
{
    options.Authority = "http://keycloak:5002/realms/test-realm";
    options.Audience = "api-gw";
    options.RequireHttpsMetadata = false;
    
    // 仅修改需要调整的参数,保留中间件自动加载的密钥等配置
    options.TokenValidationParameters.ClockSkew = TimeSpan.Zero;
    options.TokenValidationParameters.ValidAudience = "api-gw";
    
    // 事件代码保持不变
    options.Events = new JwtBearerEvents{...};
});

2. 统一容器内部的KeyCloak访问地址

网关运行在Docker容器中,需使用容器网络内的KeyCloak地址(容器名keycloak)而非宿主机localhost,否则会出现Issuer不匹配、密钥加载失败的问题:

  • 将options.Authority和ValidIssuer统一改为http://keycloak:5002/realms/test-realm
  • 无需手动设置MetadataAddress,中间件会自动通过Authority推导OIDC配置地址

3. 确保认证Scheme匹配

将默认认证Scheme设置为KeyCloak,与Ocelot路由配置中的AuthenticationProviderKey一致:

builder.Services
    .AddAuthentication("KeyCloak") // 设置默认Scheme为KeyCloak
    .AddJwtBearer("KeyCloak", options => {...});

内容的提问来源于stack exchange,提问作者Corgam

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 11:59:55