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

.NET C#实现JWT授权时持续出现签名密钥未找到错误

JWT授权报错排查:Bearer error="invalid_token", error_description="The signature key was not found"

问题描述

在C# .NET中实现JWT授权时,反复收到错误:Bearer error="invalid_token", error_description="The signature key was not found"。已将多数校验项设为false简化配置,但错误仍未解决。

相关代码与配置

身份验证与授权配置方法

public static void ApplyJwtServices(this IServiceCollection services,
    Action<AuthenticationOptions>? authenticationOptions = null,
    Action<AuthorizationOptions>? authorizationOptions = null)
{
    JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

    if (authenticationOptions != null)
    {
        services
            .AddAuthentication(authenticationOptions)
            .AddJwtBearer(options => { options.TokenValidationParameters = ValidationParameters; });
    }
    else
    {
        services
            .AddAuthentication(auth =>
            {
                auth.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
                auth.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                auth.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(options => { options.TokenValidationParameters = ValidationParameters; });
    }

    if (authorizationOptions != null)
    {
        services
            .AddAuthorization(authorizationOptions);
    }
    else
    {
        services.AddAuthorization();
    }
}

已在Program.cs中调用UseAuthentication()、UseAuthorization(),并通过builder.Services.ApplyJwtServices();启用上述配置。

JWT Token生成代码

public static string Generate(Dictionary<string, object>? claims = null, DateTime? expiresAt = null, string? audience = null)
{
    var tokenDescriptor = new SecurityTokenDescriptor
    {
        Expires = expiresAt ?? DateTime.UtcNow.AddHours(1),
        Claims = new Dictionary<string, object>
        {
            {JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()}
        },
        SigningCredentials = new SigningCredentials(ValidationParameters.IssuerSigningKey, SecurityAlgorithms.HmacSha256),
        Audience = audience ?? default
    };

    if (!string.IsNullOrEmpty(SignumIdGlobal.ApplicationSettings.JwtOptions.EncryptionKey))
    {
        tokenDescriptor.EncryptingCredentials = new EncryptingCredentials(
            new SymmetricSecurityKey(
                Encoding.UTF8.GetBytes(SignumIdGlobal.ApplicationSettings.JwtOptions.EncryptionKey)),
            SecurityAlgorithms.Aes128KW, SecurityAlgorithms.Aes128CbcHmacSha256);
    }

    if (claims != null)
    {
        foreach (var claim in claims)
        {
            tokenDescriptor.Claims.Add(claim.Key, claim.Value);
        }
    }

    var tokenHandler = new JwtSecurityTokenHandler();
    var token = tokenHandler.CreateToken(tokenDescriptor);
    return tokenHandler.WriteToken(token);
}

appsettings配置

"SecretKey": "c2lnbnVtaWRqd3R0b2tlbnNlY3JldA==",
"RequireAudience" : false,
"ValidateIssuerSigningKey": false,
"ValidateAudience": false,
"ValidateIssuer": false,
"RequireSignedTokens" : false

Token验证参数配置

new()
{
    RequireAudience = SignumIdGlobal.ApplicationSettings.JwtOptions.RequireAudience,
    IssuerSigningKey =
        new SymmetricSecurityKey(
            Encoding.UTF8.GetBytes(SignumIdGlobal.ApplicationSettings.JwtOptions.SecretKey)),
    TokenDecryptionKey = string.IsNullOrEmpty(SignumIdGlobal.ApplicationSettings.JwtOptions.EncryptionKey)
        ? null
        : new SymmetricSecurityKey(
            Encoding.UTF8.GetBytes(SignumIdGlobal.ApplicationSettings.JwtOptions.EncryptionKey)),
    ValidateIssuerSigningKey = SignumIdGlobal.ApplicationSettings.JwtOptions.ValidateIssuerSigningKey,
    ValidateAudience = SignumIdGlobal.ApplicationSettings.JwtOptions.ValidateAudience,
    ValidateIssuer = SignumIdGlobal.ApplicationSettings.JwtOptions.ValidateIssuer,
    ValidAudiences = SignumIdGlobal.ApplicationSettings.JwtOptions.ValidAudiences ?? new List<string>(),
    ValidIssuers = SignumIdGlobal.ApplicationSettings.JwtOptions.ValidIssuers ?? new List<string>(),
    ValidateActor = SignumIdGlobal.ApplicationSettings.JwtOptions.ValidateActor,
    ValidateLifetime = SignumIdGlobal.ApplicationSettings.JwtOptions.ValidateLifetime,
    ValidTypes = SignumIdGlobal.ApplicationSettings.JwtOptions.ValidTypes ?? new List<string>(),
    RequireExpirationTime = SignumIdGlobal.ApplicationSettings.JwtOptions.RequireExpirationTime,
    RequireSignedTokens = SignumIdGlobal.ApplicationSettings.JwtOptions.RequireSignedTokens,
    TryAllIssuerSigningKeys = SignumIdGlobal.ApplicationSettings.JwtOptions.TryAllIssuerSigningKeys,
    IgnoreTrailingSlashWhenValidatingAudience = SignumIdGlobal.ApplicationSettings.JwtOptions
        .IgnoreTrailingSlashWhenValidatingAudience
}

生成的JWT示例

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI0YmNjZWNmOC1mNTNhLTQ3ZjMtYWQ3Yi1kYTE2Zjc4OWJmYTUiLCJuYmYiOjE2Nzg2Mzc1MDIsImV4cCI6MTY3ODY0MTEwMiwiaWF0IjoxNjc4NjM3NTAyfQ.0rihJAzJ3Yc0yiRSWXLYViSN0qmYWvTiShWy8Qq2iZg


解决方案

核心问题:密钥处理错误

你的SecretKey是Base64编码格式,但代码中直接用Encoding.UTF8.GetBytes()将Base64字符串本身转换为字节数组,而非解码Base64得到原始密钥。这导致生成Token和验证Token时使用的密钥不一致,触发签名密钥未找到的错误。

修复步骤

  1. 修正密钥解码逻辑
    将验证参数中的IssuerSigningKey创建代码修改为Base64解码:

    IssuerSigningKey = new SymmetricSecurityKey(
        Convert.FromBase64String(SignumIdGlobal.ApplicationSettings.JwtOptions.SecretKey)),
    

    由于Token生成代码依赖ValidationParameters.IssuerSigningKey,修正后生成签名时会自动使用正确的密钥。

  2. 验证密钥匹配
    用以下代码测试修正后的密钥能否验证示例Token:

    var tokenHandler = new JwtSecurityTokenHandler();
    var validationParams = new TokenValidationParameters
    {
        IssuerSigningKey = new SymmetricSecurityKey(Convert.FromBase64String("c2lnbnVtaWRqd3R0b2tlbnNlY3JldA==")),
        ValidateIssuer = false,
        ValidateAudience = false,
    };
    try
    {
        tokenHandler.ValidateToken("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI0YmNjZWNmOC1mNTNhLTQ3ZjMtYWQ3Yi1kYTE2Zjc4OWJmYTUiLCJuYmYiOjE2Nzg2Mzc1MDIsImV4cCI6MTY3ODY0MTEwMiwiaWF0IjoxNjc4NjM3NTAyfQ.0rihJAzJ3Yc0yiRSWXLYViSN0qmYWvTiShWy8Qq2iZg", validationParams, out _);
        Console.WriteLine("Token验证通过");
    }
    catch (Exception ex)
    {
        Console.WriteLine($"验证失败:{ex.Message}");
    }
    
  3. 确认中间件顺序
    确保Program.cs中中间件调用顺序正确:

    app.UseAuthentication();
    app.UseAuthorization();
    

    UseAuthentication()必须在UseAuthorization()之前,否则验证逻辑不会生效。

  4. 检查配置一致性
    即使ValidateIssuerSigningKey设为false,只要生成的Token带有签名,验证环节仍会校验签名有效性,因此必须保证密钥完全匹配。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 00:17:02