【问题标题】:SecurityTokenSignatureKeyNotFoundException with multiple authentication schemes具有多种身份验证方案的 SecurityTokenSignatureKeyNotFoundException
【发布时间】:2021-07-05 23:27:57
【问题描述】:

我有一个设置了应用注册的 Azure Active Directory。我有一个 B2C 租户,其中包含应用注册并设置了多个用户流。

在 Startup.cs 中,我配置了多个身份验证方案,如下所示。

services
    .AddAuthentication()
    .AddJwtBearer("Azure", options => 
    {
        options.Audience = "clientId";
        options.Authority = "https://login.microsoftonline.com/tenantId";
    })
    .AddJwtBearer("AzureB2cCustomerSignIn", options => 
    {
        options.Audience = "clientIdInB2c";
        options.Authority = "https://tentantName.b2clogin.com/tenantName.onmicrosoft.com/userFlowName/v2.0";
    })
    .AddJwtBearer("AzureB2cCustomerSignUp", options => 
    {
        options.Audience = "clientIdInB2c";
        options.Authority = "https://tentantName.b2clogin.com/tenantName.onmicrosoft.com/userFlowName/v2.0";
    })
    .AddJwtBearer("AzureB2cEmployeeSignUpAndSignIn", options => 
    {
        options.Audience = "clientIdInB2c";
        options.Authority = "https://tentantName.b2clogin.com/tenantName.onmicrosoft.com/userFlowName/v2.0";
    });

services
    .AddAuthorization(options =>
    {
        options.DefaultPolicy = new AuthorizationPolicyBuilder()
            .RequireAuthenticatedUser()
            .AddAuthenticationSchemes("Azure", "AzureB2cCustomerSignIn", "AzureB2cCustomerSignUp", "AzureB2cEmployeeSignUpAndSignIn")
            .Build();
    }

当我尝试使用来自 B2C 流的令牌进行身份验证时,我收到了以下单个错误。应用程序可以继续,API 方法被执行,一切正常。但这会严重混淆应用程序洞察力和错误。更重要的是,很可能还会影响性能。我一定是缺少一些配置...

Microsoft.IdentityModel.Tokens.SecurityTokenSignatureKeyNotFoundException: IDX10501: Signature validation failed. Unable to match key: 
kid: 'System.String'.
Exceptions caught:
 'System.Text.StringBuilder'. 
token: 'System.IdentityModel.Tokens.Jwt.JwtSecurityToken'.
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, TokenValidationParameters validationParameters, SecurityToken& validatedToken)
   at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler: Information: Azure was not authenticated. Failure message: IDX10501: Signature validation failed. Unable to match key: 
kid: 'System.String'.
Exceptions caught:
 'System.Text.StringBuilder'. 
token: 'System.IdentityModel.Tokens.Jwt.JwtSecurityToken'.

它指出无法根据我为 Azure Active Directory 配置的身份验证方案验证令牌,这很明显。由于它是来自 B2C 身份验证流程的令牌,我什至不希望它尝试使用此身份验证方案进行身份验证。从逻辑上讲,当我使用来自 AAD 流的令牌进行身份验证时,我得到了三次 SecurityTokenSignatureKeyNotFoundException

我怎样才能避免这个错误?

【问题讨论】:

    标签: asp.net-core


    【解决方案1】:

    该问题的一种解决方案是添加一个自定义 JwtBearerHandler,它知道令牌的颁发者,并且仅当令牌颁发者与身份验证方案颁发者相同时才验证令牌。

    自定义处理程序的代码如下。

    public class CustomJwtHandler : JwtBearerHandler
    {
        public CustomJwtHandler(
            IOptionsMonitor<JwtBearerOptions> options,
            ILoggerFactory logger,
            UrlEncoder encoder,
            ISystemClock clock)
            : base(options, logger, encoder, clock)
        {
        }
    
        protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
        {
            var authenticationSchemeConfiguration = await this.Options.ConfigurationManager.GetConfigurationAsync(this.Context.RequestAborted);
            var jwt = this.ReadTokenFromHeader();
            var jwtHandler = new JwtSecurityTokenHandler();
    
            if (jwtHandler.CanReadToken(jwt))
            {
                var token = jwtHandler.ReadJwtToken(jwt);
                if (string.Equals(token.Issuer, authenticationSchemeConfiguration.Issuer, StringComparison.OrdinalIgnoreCase))
                {
                    return await base.HandleAuthenticateAsync();
                }
                else
                {
                    return AuthenticateResult.NoResult();
                }
            }
    
            return await base.HandleAuthenticateAsync();
        }
    
        private string ReadTokenFromHeader()
        {
            var authorization = Request.Headers["Authorization"].ToString();
    
            if (string.IsNullOrEmpty(authorization))
            {
                return null;
            }
    
            if (authorization.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
            {
                return authorization.Substring(7).Trim();
            }
    
            return null;
        }
    }
    

    自定义处理程序的接线如下。注意必须添加的附加服务,没有它,自定义处理程序中的 JwtBearerOptions 为 null,导致调用 GetConfigurationAsync 时出现 NullReferenceException。

    services
        .AddAuthentication()
        .AddScheme<JwtBearerOptions, CustomJwtHandler>("Azure", options => Configuration.Bind("AzureJwtBearerOptions", options))
        .AddScheme<JwtBearerOptions, CustomJwtHandler>("AzureB2cCustomerSignIn", options => Configuration.Bind("AzureB2cCustomerSignInJwtBearerOptions", options))
        .AddScheme<JwtBearerOptions, CustomJwtHandler>("AzureB2cCustomerSignUp", options => Configuration.Bind("AzureB2cCustomerSignUpJwtBearerOptions", options))
        .AddScheme<JwtBearerOptions, CustomJwtHandler>("AzureB2cEmployeeSignUpAndSignIn", options => Configuration.Bind("AzureB2cEmployeeSignUpAndSignInJwtBearerOptions", options))
        .Services.TryAddEnumerable(ServiceDescriptor.Singleton<IPostConfigureOptions<JwtBearerOptions>, JwtBearerPostConfigureOptions>()); // Without this JwtBearerOptions.ConfigurationManager is null.
    

    【讨论】:

      猜你喜欢
      • 2021-11-27
      • 2019-08-31
      • 2018-08-08
      • 2021-10-18
      • 1970-01-01
      • 2022-01-04
      • 2011-04-15
      • 2018-03-23
      • 2022-10-05
      相关资源
      最近更新 更多