使用Duende IdentityServer与Docker Compose时API授权返回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

