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

容器化.NET 8 ASP.NET API的JWT验证失败与网络请求问题

问题描述

我正在将.NET 8版本的ASP.NET Web API进行容器化处理。该API在Visual Studio本地运行及Azure部署时均正常,使用从Entra获取的JWT调用接口毫无问题,授权配置如下:

// Add authentication services
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        builder.Configuration.Bind("AzureAd", options);

        options.Authority = $"{builder.Configuration["AzureAd:Instance"]}{builder.Configuration["AzureAd:TenantId"]}/v2.0";

        // The valid audiences are both the Client ID(options.Audience) and api://{ClientID}
        options.TokenValidationParameters.ValidAudiences =
        [
            builder.Configuration["AzureAd:ClientId"], 
            $"api://{builder.Configuration["AzureAd:ClientId"]}",            
        ];

        // Valid issuers here:
        options.TokenValidationParameters.ValidIssuers =
        [
            $"https://sts.windows.net/{builder.Configuration["AzureAd:TenantId"]}/",
            $"{builder.Configuration["AzureAd:Instance"]}{builder.Configuration["AzureAd:TenantId"]}/",
            $"https://login.microsoftonline.com/{builder.Configuration["AzureAd:TenantId"]}/v2.0"
        ];
    });

但容器化后,无需授权的接口可正常调用,调用带有[Authorize]属性的控制器方法时却返回401 Unauthorized,响应头信息如下:

content-length: 0 
 date: Tue,16 Apr 2024 19:17:36 GMT 
 server: Kestrel 
 www-authenticate: Bearer error="invalid_token",error_description="The signature key was not found" 

相同代码在本地运行正常,容器中则无法工作。推测是JWT验证代码尝试从Authority获取签名密钥时失败,本地环境允许该出站请求,但容器环境未允许。

为验证该假设,在控制器中添加测试方法:

var client = new HttpClient();
client.BaseAddress = new Uri("https://www.microsoft.com/");
var resp = await client.GetAsync(string.Empty);
html = await resp.Content.ReadAsStringAsync();

测试容器是否能发起任何出站请求,结果失败,错误信息如下:

System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
 ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid because of errors in the certificate chain: UntrustedRoot

不想在容器中手动安装证书或密钥(担心证书变更),请问是否有办法解决容器内的出站HTTP请求问题?

解决方案

以下几种方法可解决容器内SSL证书信任问题,无需手动安装证书:

1. 切换到完整版本的官方.NET基础镜像

若当前使用mcr.microsoft.com/dotnet/aspnet:8.0-alpine这类轻量镜像,替换为非Alpine的完整镜像(如mcr.microsoft.com/dotnet/aspnet:8.0)。这类镜像预装了完整的根证书信任链,可自动信任主流CA颁发的证书,包括Microsoft服务的证书。

2. 临时禁用证书验证(仅测试环境)

如果是测试环境排查问题,可在JWTBearer配置中跳过证书验证,但生产环境严禁使用:

.AddJwtBearer(options =>
{
    // 保留原有配置...
    options.BackchannelHttpHandler = new HttpClientHandler
    {
        ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
    };
})

3. 挂载主机证书目录到容器

运行容器时,将主机的证书目录挂载到容器对应路径,让容器直接使用主机的信任证书:

  • Windows主机:
    docker run -v "C:\Windows\System32\config\systemprofile\AppData\Local\Microsoft\Windows\Certificates:/root/.aspnet/https" your-image-name
    
  • Linux主机:
    docker run -v "/etc/ssl/certs:/etc/ssl/certs:ro" your-image-name
    

4. 配置HttpClient使用系统默认证书验证

对于.NET 8,默认HttpClient会尝试读取系统证书存储。如果使用自定义HttpClient,确保未覆盖证书验证逻辑:

builder.Services.AddHttpClient("MicrosoftServices", client =>
{
    client.BaseAddress = new Uri("https://login.microsoftonline.com/");
}).ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
{
    UseDefaultCredentials = true,
    ServerCertificateCustomValidationCallback = HttpClientHandler.DefaultServerCertificateCustomValidationCallback
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 16:38:17