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

如何调试.NET 8中AWS Cognito JWT Bearer认证未通过问题

问题描述

我正在将一个运行了9年、从未改动过的.NET Core 1.1 MVC Web服务升级到.NET 8.0,目前需要让服务验证AWS Cognito的Bearer令牌。我已经正确配置了Issuer(确认其字符串与解码JWT中的iss字段完全匹配),但调试输出仅显示:

Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler: Debug: AuthenticationScheme: Bearer was not authenticated.

我已经将默认日志级别设置为Trace,并且单独指定了各组件的Trace级别:

{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Trace",
"System": "Trace",
"Microsoft": "Trace",
"Microsoft.AspNetCore": "Trace",
"Microsoft.AspNetCore.Authentication": "Trace"
}
}
}

同时我设置了多项JwtBearer选项以增加日志信息:

options.TokenValidationParameters = new TokenValidationParameters
{
    RequireSignedTokens = true,
    RequireExpirationTime = true,
    ClockSkew = new TimeSpan(0, 15, 0),
    RequireAudience = false,
    ValidateAudience = false,
    ValidateLifetime = true,
    ValidateIssuer = true,
    ValidIssuer = "proper aws url",
    LogValidationExceptions = true,
    LogTokenId = true,
};
options.UseSecurityTokenValidators = true;
options.IncludeErrorDetails = true;

但生成的跟踪日志仍极为有限(仅一行)且不明确。我肯定遗漏了某些配置,请问如何调试找出验证失败的原因?是否可以在认证链中插入自定义类,以查看哪个函数失败、传入的参数等信息?


解决方案

1. 补全签名验证配置(最可能的遗漏点)

你当前只配置了Issuer验证,但JWT签名验证是核心环节——AWS Cognito的令牌需要用对应公钥验证签名。.NET 8的JwtBearer不会自动获取Cognito的公钥,必须手动配置:

options.TokenValidationParameters.IssuerSigningKeyResolver = (token, securityToken, kid, validationParameters) =>
{
    // 替换为你的Cognito区域和用户池ID
    var jwksUrl = $"https://cognito-idp.{region}.amazonaws.com/{userPoolId}/.well-known/jwks.json";
    using var httpClient = new HttpClient();
    var jwks = httpClient.GetStringAsync(jwksUrl).Result;
    var keys = new JsonWebKeySet(jwks).GetSigningKeys();
    return keys.Where(k => k.Kid == kid);
};

如果只是临时测试,可以设置RequireSignedTokens = false跳过签名验证,但生产环境必须开启该验证。

2. 手动捕获验证异常

即使开启了LogValidationExceptions,有时日志框架可能无法正确输出异常详情。可以通过自定义JwtBearerEvents直接捕获并打印:

options.Events = new JwtBearerEvents
{
    OnAuthenticationFailed = context =>
    {
        Console.WriteLine($"认证失败: {context.Exception.Message}");
        if (context.Exception.InnerException != null)
        {
            Console.WriteLine($"内部异常: {context.Exception.InnerException.Message}");
        }
        return Task.CompletedTask;
    },
    OnTokenValidated = context =>
    {
        Console.WriteLine("令牌验证成功");
        return Task.CompletedTask;
    }
};

这个事件会在验证失败时触发,直接返回具体错误原因(比如签名不匹配、令牌过期、Issuer不一致等)。

3. 插入自定义令牌验证器

如果需要更深入的调试,可以实现ISecurityTokenValidator来监控验证全流程:

public class DebugTokenValidator : ISecurityTokenValidator
{
    private readonly JwtSecurityTokenHandler _innerValidator = new JwtSecurityTokenHandler();

    public bool CanValidateToken => true;
    public int MaximumTokenSizeInBytes => _innerValidator.MaximumTokenSizeInBytes;

    public bool CanReadToken(string securityToken)
    {
        Console.WriteLine($"收到令牌: {securityToken}");
        return _innerValidator.CanReadToken(securityToken);
    }

    public ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken)
    {
        try
        {
            Console.WriteLine("开始令牌验证...");
            Console.WriteLine($"配置的ValidIssuer: {validationParameters.ValidIssuer}");
            var principal = _innerValidator.ValidateToken(securityToken, validationParameters, out validatedToken);
            Console.WriteLine("验证成功");
            return principal;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"验证失败: {ex.Message}");
            throw;
        }
    }
}

然后替换默认验证器:

options.SecurityTokenValidators.Clear();
options.SecurityTokenValidators.Add(new DebugTokenValidator());

该自定义验证器会在验证前后输出关键参数,帮你定位具体出错步骤。

4. 检查令牌本身的有效性

先用JWT解码工具(比如本地jwt命令行工具)解码令牌,确认:

  • iss字段和配置的ValidIssuer完全一致(注意大小写、末尾是否带斜杠)
  • exp字段是否在有效期内
  • kid字段存在且能在Cognito的JWKS端点找到对应公钥

5. 确认中间件注册顺序

在.NET 8中,认证中间件的顺序至关重要,确保UseAuthentication()在UseAuthorization()之前,且在MapControllers()之前:

var builder = WebApplication.CreateBuilder(args);
// 注册服务
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options => { /* 你的配置 */ });
builder.Services.AddAuthorization();

var app = builder.Build();
// 中间件顺序
app.UseHttpsRedirection();
app.UseAuthentication(); // 必须在UseAuthorization之前
app.UseAuthorization();
app.MapControllers();
app.Run();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 06:27:13