我有一个已设置应用注册的 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
。
我怎样才能避免这个错误?
答案 0 :(得分:0)
该问题的一个解决方案是添加一个自定义 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.