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

.NET Core 6 Web API:多Bearer验证器,避免错误日志冗余

解决.NET Core 6 Web API多Bearer认证冗余日志问题

方法一:给每个认证方案添加颁发者预校验逻辑

在配置每个JWT Bearer认证方案时,通过Events在验证开始前先解析令牌的颁发者,若与当前方案的有效颁发者不匹配,直接终止当前方案的验证流程,避免产生错误日志。

示例代码:

services.AddAuthentication()
    .AddJwtBearer("Scheme1", options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidIssuer = "https://issuer1.com",
            // 其他验证参数(如ValidAudience、IssuerSigningKey等)
        };

        options.Events = new JwtBearerEvents
        {
            OnMessageReceived = context =>
            {
                var token = context.Request.Headers["Authorization"].ToString().Replace("Bearer ", "");
                if (!string.IsNullOrEmpty(token))
                {
                    try
                    {
                        var handler = new JwtSecurityTokenHandler();
                        var jwtToken = handler.ReadJwtToken(token);
                        if (jwtToken.Issuer != options.TokenValidationParameters.ValidIssuer)
                        {
                            // 颁发者不匹配,终止当前方案验证
                            context.Fail("Issuer does not match for this scheme");
                        }
                    }
                    catch
                    {
                        // 令牌格式无效,直接终止
                        context.Fail("Invalid token format");
                    }
                }
                return Task.CompletedTask;
            }
        };
    })
    .AddJwtBearer("Scheme2", options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidIssuer = "https://issuer2.com",
            // 其他验证参数
        };

        options.Events = new JwtBearerEvents
        {
            OnMessageReceived = context =>
            {
                var token = context.Request.Headers["Authorization"].ToString().Replace("Bearer ", "");
                if (!string.IsNullOrEmpty(token))
                {
                    try
                    {
                        var handler = new JwtSecurityTokenHandler();
                        var jwtToken = handler.ReadJwtToken(token);
                        if (jwtToken.Issuer != options.TokenValidationParameters.ValidIssuer)
                        {
                            context.Fail("Issuer does not match for this scheme");
                        }
                    }
                    catch
                    {
                        context.Fail("Invalid token format");
                    }
                }
                return Task.CompletedTask;
            }
        };
    });

这里的context.Fail()会标记当前认证方案失败,但不会抛出异常,也就不会生成冗余错误日志,后续认证方案仍会继续执行直到找到匹配的。

方法二:为不同端点指定专属认证方案

如果API端点可以按业务划分对应不同颁发者,直接在端点路由上指定允许的认证方案,让每个端点的请求只被对应验证器处理,从根源避免冗余校验。

示例代码:

// 全局为某组控制器指定认证方案
app.MapControllers()
    .RequireAuthorization(new AuthorizeAttribute { AuthenticationSchemes = "Scheme1" });

// 针对单个控制器/方法指定
[ApiController]
[Route("api/[controller]")]
[Authorize(AuthenticationSchemes = "Scheme2")]
public class SecondController : ControllerBase
{
    // 控制器方法逻辑
}

方法三:自定义JWT认证处理程序

继承JwtBearerHandler,重写HandleAuthenticateAsync方法,在验证前先检查令牌颁发者,不匹配则直接返回AuthenticateResult.NoResult(),跳过验证流程。

示例代码:

public class IssuerFilteredJwtHandler : JwtBearerHandler
{
    private readonly string _validIssuer;

    public IssuerFilteredJwtHandler(IOptionsMonitor<JwtBearerOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, string validIssuer)
        : base(options, logger, encoder, clock)
    {
        _validIssuer = validIssuer;
    }

    protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        var authHeader = Context.Request.Headers["Authorization"].ToString();
        if (!authHeader.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
        {
            return AuthenticateResult.NoResult();
        }

        var token = authHeader.Substring("Bearer ".Length).Trim();
        if (string.IsNullOrEmpty(token))
        {
            return AuthenticateResult.NoResult();
        }

        try
        {
            var handler = new JwtSecurityTokenHandler();
            var jwtToken = handler.ReadJwtToken(token);
            if (jwtToken.Issuer != _validIssuer)
            {
                return AuthenticateResult.NoResult();
            }
        }
        catch
        {
            return AuthenticateResult.NoResult();
        }

        // 调用父类的标准验证逻辑
        return await base.HandleAuthenticateAsync();
    }
}

注册自定义处理程序:

services.AddAuthentication()
    .AddScheme<JwtBearerOptions, IssuerFilteredJwtHandler>("Scheme1", options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidIssuer = "https://issuer1.com",
            // 其他验证参数
        };
    }, resolver => new IssuerFilteredJwtHandler(
        resolver.GetRequiredService<IOptionsMonitor<JwtBearerOptions>>(),
        resolver.GetRequiredService<ILoggerFactory>(),
        resolver.GetRequiredService<UrlEncoder>(),
        resolver.GetRequiredService<ISystemClock>(),
        "https://issuer1.com"
    ))
    .AddScheme<JwtBearerOptions, IssuerFilteredJwtHandler>("Scheme2", options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidIssuer = "https://issuer2.com",
            // 其他验证参数
        };
    }, resolver => new IssuerFilteredJwtHandler(
        resolver.GetRequiredService<IOptionsMonitor<JwtBearerOptions>>(),
        resolver.GetRequiredService<ILoggerFactory>(),
        resolver.GetRequiredService<UrlEncoder>(),
        resolver.GetRequiredService<ISystemClock>(),
        "https://issuer2.com"
    ));

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 20:35:25