使用Keycloak与.NET Core集成时出现签名密钥未找到错误
解决Docker环境下.NET Core WebAPI对接Keycloak时的签名密钥找不到问题
你的配置与错误信息
认证配置代码
services .AddAuthentication(options => { options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultSignInScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultForbidScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options => { options.MetadataAddress = "http://localhost:8080/auth/realms/{my_realm}/.well-known/openid-configuration"; options.Authority = "http://localhost:8080/auth/realms/{my_realm}"; options.Audience = "{my_audience}"; options.TokenValidationParameters = new TokenValidationParameters { ValidAudience = "{my_audience}", ValidIssuers = ["http://localhost:8080/auth/realms/{my_realm}", "https://localhost:8080/auth/realms/{my_realm}"] }; options.RequireHttpsMetadata = false; options.SaveToken = true; });
错误提示
- 响应头错误:
www-authenticate: Bearer error="invalid_token",error_description="The signature key was not found" - DEBUG日志错误:
Microsoft.IdentityModel.Tokens.SecurityTokenSignatureKeyNotFoundException: IDX10500: Signature validation failed. No security keys were provided to validate the signature.
问题根源
你用了localhost:8080作为Keycloak的访问地址,但Docker容器内部的localhost指向容器自身,而非宿主机。这导致WebAPI容器无法访问到Keycloak容器,自然拉取不到OIDC元数据(包含验证签名所需的公钥),最终触发签名验证失败。
修复方案
1. 改用Docker容器名称/服务名访问Keycloak
Docker容器在同一个网络内可以通过容器名称互相访问,步骤如下:
- 确保WebAPI和Keycloak容器处于同一个Docker网络(如果没有,先创建:
docker network create keycloak-net) - 把配置中的
localhost替换成Keycloak的容器名称(假设Keycloak容器名为keycloak)
2. 同步Token验证的Issuer配置
Keycloak生成的Token中iss字段是它自身的访问地址,需要和ValidIssuers保持一致,否则也会验证失败。
修改后的完整配置
services .AddAuthentication(options => { options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultSignInScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultForbidScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options => { // 替换为你的Keycloak容器名称 var keycloakContainerName = "keycloak"; options.MetadataAddress = $"http://{keycloakContainerName}:8080/auth/realms/{my_realm}/.well-known/openid-configuration"; options.Authority = $"http://{keycloakContainerName}:8080/auth/realms/{my_realm}"; options.Audience = "{my_audience}"; options.TokenValidationParameters = new TokenValidationParameters { ValidAudience = "{my_audience}", // 与Keycloak生成Token的issuer保持一致 ValidIssuers = new[] { $"http://{keycloakContainerName}:8080/auth/realms/{my_realm}" } }; options.RequireHttpsMetadata = false; options.SaveToken = true; });
额外注意事项
- 如果用Docker Compose管理容器,直接在
docker-compose.yml中定义同一个网络,服务之间可以用服务名(比如keycloak)互相访问,无需手动创建网络。 - 若需要从宿主机访问Keycloak,仍可以用
localhost:8080,但容器间通信必须用容器名称/服务名。
内容的提问来源于stack exchange,提问作者ELOL
相关产品推荐
相关产品推荐

