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

使用Duende IdentityServer与Docker Compose时API授权返回401无效令牌错误

Docker环境下Duende IdentityServer令牌验证401问题排查

我使用Docker、.NET 8和Angular搭建项目,通过Duende IdentityServer获取令牌保护API接口,但无论通过Angular登录后发送令牌,还是在Postman中使用m2m.client客户端通过客户端凭证流请求,API始终返回401错误提示“invalid token”。本地未使用Docker时,相同配置的客户端凭证流可正常工作,Docker环境下则报错。

IdentityServer配置

public static class Config
{
    public static IEnumerable<IdentityResource> IdentityResources =>
        new IdentityResource[]
        {
            new IdentityResources.OpenId(),
            new IdentityResources.Profile()
        };

    public static IEnumerable<ApiScope> ApiScopes =>
       new ApiScope[]
       {
            new ApiScope("scope1"),
            new ApiScope("scope2"),
       };

    public static IEnumerable<Client> Clients =>
            new Client[]
            {
                // m2m client credentials flow client
                new Client
                {
                    ClientId = "m2m.client",
                    ClientName = "Client Credentials Client",

                    AllowedGrantTypes = GrantTypes.ClientCredentials,
                    ClientSecrets = { new Secret("511536EF-F270-4058-80CA-1C89C192F69A".Sha256()) },

                    AllowedScopes = { "scope1" }
                },
                new Client
                {
                    ClientId = "frontend",
                    ClientName = "Angular frontend",
                    AllowedGrantTypes = GrantTypes.Code,
                    //RequireClientSecret = false,
                    ClientSecrets = { new Secret("secret".Sha256()) },
                    AllowOfflineAccess = true,

                    RedirectUris =           { "http://localhost:4200/silent-refresh.html", "http://localhost:4200", "http://localhost:4200/" },
                    PostLogoutRedirectUris = { "http://localhost:4200/index.html" },
                    AllowedCorsOrigins =     { "http://localhost:4200" },

                    AllowedScopes =
                    {
                        "openid",
                        "profile",
                        "scope1"
                    },
                }
            };
}

API的Program.cs配置

builder.Services.AddAuthentication("token")
                .AddJwtBearer("token", options =>
                {
                    options.Authority = "http://localhost:5200";
                    options.TokenValidationParameters.ValidateAudience = false;
                    options.RequireHttpsMetadata = false;

                    options.TokenValidationParameters.ValidTypes = new[] { "at+jwt" };
                });

Docker Compose配置

version: '3.4'

services:
  identityserver:
    image: identityserver
    container_name: identityserver
    build:
      context: ./TestProject.Service.Core
      dockerfile: ./IdentityServer/Dockerfile
    ports:
      - "5200:8080"
      - "5201:8081"
    environment:
      - ASPNETCORE_ENVIRONMENT=Development

  core.database:
    image: postgres:latest
    container_name: core.database
    environment:
      - POSTGRES_DB=core
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
    volumes:
      - ./.containers/core-db:/var/lib/postgresql/data
    ports:
      - 3376:5432

  test.api:
    image: testapi
    container_name: test.api
    build:
      context: ./TestApi
      dockerfile: ./Api/Dockerfile
    ports:
      - "5040:8080"
      - "5041:8081"
    environment:
      - ASPNETCORE_ENVIRONMENT=Development

  frontend:
    image: frontend
    build:
      context: ./Limber.Frontend/limber.frontend
      dockerfile: ./dockerfile
    ports:
      - 4200:80

错误现象

Docker环境下出现两种401错误:

  • 未禁用ValidateIssuer时:Bearer error="invalid_token", error_description="The issuer 'http://localhost:5200' is invalid"
  • 禁用ValidateIssuer后:Bearer error="invalid_token", error_description="The signature key was not found"

解决方案

1. 修正容器间通信的Authority地址

Docker容器内,API访问IdentityServer不能使用localhost:5200(容器的localhost指向自身而非宿主机),需改用Docker Compose的服务名identityserver加容器内部端口:

// API的Program.cs修改Authority配置
options.Authority = "http://identityserver:8080";

2. 统一IdentityServer的Issuer URI

IdentityServer在容器内会自动检测自身地址,可能生成的issuer为http://identityserver:8080,但外部(Postman/Angular)请求令牌时使用的是http://localhost:5200,导致令牌内的issuer与API验证时的地址不匹配。需在IdentityServer的Program.cs中强制指定Issuer URI:

builder.Services.AddIdentityServer(options =>
{
    options.IssuerUri = "http://localhost:5200"; // 与外部访问地址保持一致
})
.AddInMemoryIdentityResources(Config.IdentityResources)
.AddInMemoryApiScopes(Config.ApiScopes)
.AddInMemoryClients(Config.Clients)
.AddDeveloperSigningCredential();

3. 确保签名证书一致性

开发环境下IdentityServer默认使用临时签名证书,容器重启会重新生成证书,导致API无法获取正确公钥验证签名。可通过以下方式解决:

  • 生成固定的开发证书,挂载到IdentityServer容器中;
  • 在IdentityServer的Program.cs中明确指定使用固定证书(仅开发环境临时使用):
builder.Services.AddIdentityServer()
    .AddInMemoryIdentityResources(Config.IdentityResources)
    .AddInMemoryApiScopes(Config.ApiScopes)
    .AddInMemoryClients(Config.Clients)
    .AddSigningCredential(new X509Certificate2("path/to/your/dev-cert.pfx", "password"));

4. 验证容器网络连通性

确认test.api容器能连通identityserver服务,在test.api容器内执行:

ping identityserver

Docker Compose默认会将所有服务加入同一网络,若不通需检查网络配置是否被修改。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 02:45:56