首页 > 解决方案 > IDX10501:签名验证失败。无法匹配键

问题描述

请帮助我了解来自 ASP netcore 应用程序和 netcore Kestrel 托管应用程序的 JWT 令牌验证之间的区别。

有两个应用程序使用如下源代码验证令牌:

public static IServiceCollection AddJwtToken(this IServiceCollection services, OAuthConfig config)
{
    services.AddMvc();
    services.AddAuthorization();

    Logger.DebugFormat("AddJwtBearer authority:{0} audience:{1}", config.GetAuthority(), config.Resource);

    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options => new JwtBearerOptions
        {
            Authority = config.GetAuthority(),
            Audience = config.Resource,
    });

    return services;
}

它非常简单,如果从 asp net core 2.2 应用程序验证令牌,它工作得很好

// in the asp.net core
var builder = WebHost.CreateDefaultBuilder(args);
builder
        .UseStartup<Startup>()
        .ConfigureKestrel(_ => _.ConfigureEndpoints())
        .UseSerilog();

还有另一个应用程序(控制台)使用UseKestrel

//in the console app
var builder = WebHost.CreateDefaultBuilder()
    .UseNLog()
    .UseKestrel(_ => _.ConfigureEndpoints())
    .UseStartup<Startup>();

唯一的一个显着区别是UseKestrel控制台中有ConfigureKestrel用于 asp.net 核心的 via。

相同的源代码(和配置)用于从 Azure AD 获取令牌。请在此处找到它作为要点。它被配置为从https://login.microsoftonline.com/{tenant}/v2.0提供者那里获取令牌。两种情况都使用相同的令牌端点、clientid、secret 和 scope 值。

问题是AddJwtBearer在 asp.net 核心中验证令牌,而不是在控制台应用程序中。错误是

Microsoft.IdentityModel.Tokens.SecurityTokenSignatureKeyNotFoundException: IDX10501: Signature validation failed. Unable to match keys:
kid: 'BB8CeFVqyaGrGNuehJIiL4dfjzw',
token: '{"typ":"JWT","alg":"RS256","kid":"BB8CeFVqyaGrGNuehJIiL4dfjzw"}.{"aud":"2c163c99-935b-4362-ae0d-657f589f5565","iss":"https://login.microsoftonline.com/{tenantidhere}/v2.0

为什么 asp.net 核心主机验证令牌(对于第一次AddJwtBearer实现)而控制台主机失败?

谢谢

标签: c#asp.net-coreazure-active-directoryopenid

解决方案


要解决此错误,我必须从 openid 提供程序加载密钥,如下所示:

Logger.DebugFormat("AddJwtBearer authority:{0} audience:{1}", config.GetAuthority(), config.Resource);

IList<string> validissuers = new List<string>()
{
    config.GetAuthority(),
};

var configManager = new ConfigurationManager<OpenIdConnectConfiguration>($"{validissuers.Last()}/.well-known/openid-configuration", new OpenIdConnectConfigurationRetriever());

var openidconfig = configManager.GetConfigurationAsync().Result;

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, _ =>
    {
        _.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters()
        {
            ValidateAudience = true,
            ValidAudience = config.Resource,

            ValidateIssuer = true,
            ValidIssuers = new[] { config.GetAuthority() },

            ValidateIssuerSigningKey = true,
            IssuerSigningKeys = openidconfig.SigningKeys,

            RequireExpirationTime = true,
            ValidateLifetime = true,
            RequireSignedTokens = true,
        };

        _.RequireHttpsMetadata = false;

    });

它开始对这两种情况都有效。AddJwtBearer但是旧实现和新实现(与密钥验证有关)有什么区别?使用 下载和提供的密钥,IssuerSigningKeys = openidconfig.SigningKeys但为什么不使用中间件自动.well-known/openid-configuration加载AddJwtBearer


推荐阅读