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

如何为.NET Core WebAPI的JWT认证及授权失败添加自定义日志

解决.NET Core WebAPI中认证失败场景的自定义日志统计问题

我之前也碰到过一模一样的问题——你的IAsyncActionFilter属于MVC管道的一部分,只有当请求能顺利走到Action执行阶段才会触发,但认证失败的请求早在MVC管道启动前就被拦截了,所以根本碰不到你的过滤器。结合你提到的JwtBearerEvents和AuthorizeFilter的问题,我给你几个实用的解决方案:

方案一:利用JwtBearerEvents覆盖全场景认证事件

你之前说JwtBearerEvents没生效,大概率是没覆盖到所有关键场景。除了AuthenticationFailed,还要处理不带Token和认证挑战的情况,修改你的JWT配置代码如下:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.Authority = Configuration["Authority"];
        options.Audience = "myAudience";

        options.Events = new JwtBearerEvents
        {
            // 捕获完全不带Token的请求
            OnMessageReceived = context =>
            {
                if (string.IsNullOrEmpty(context.Request.Headers["Authorization"]))
                {
                    // 这里记录StatsD统计,比如"api.auth.no_token"计数+1
                    // 注意:如果StatsD客户端是注入的,要通过context.HttpContext.RequestServices获取实例
                    var statsd = context.HttpContext.RequestServices.GetService<IStatsdClient>();
                    statsd?.Increment("api.auth.no_token");
                }
                return Task.CompletedTask;
            },
            // 捕获Token无效、过期等认证失败场景
            OnAuthenticationFailed = context =>
            {
                var statsd = context.HttpContext.RequestServices.GetService<IStatsdClient>();
                statsd?.Increment("api.auth.failed");
                // 可选:记录具体错误信息
                // _logger.LogError(context.Exception, "JWT认证失败");
                return Task.CompletedTask;
            },
            // 捕获认证失败后返回401挑战的场景
            OnChallenge = context =>
            {
                var statsd = context.HttpContext.RequestServices.GetService<IStatsdClient>();
                statsd?.Increment("api.auth.challenged");
                // 如果你需要自定义401响应,记得调用context.HandleResponse(),否则会用默认响应
                return Task.CompletedTask;
            }
        };
    });

方案二:添加全局自定义中间件,统一捕获所有认证失败响应

如果想统一处理所有认证类型的失败(不止JWT),可以在UseAuthentication之后、UseMvc之前加一个中间件,在请求结束后检查响应状态:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    // ...其他中间件
    app.UseAuthentication();

    // 自定义认证统计中间件
    app.Use(async (context, next) =>
    {
        await next();

        // 检查是否返回401未授权
        if (context.Response.StatusCode == StatusCodes.Status401Unauthorized)
        {
            var authenticateResult = await context.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme);
            var statsd = context.RequestServices.GetService<IStatsdClient>();
            
            if (!authenticateResult.Succeeded)
            {
                if (authenticateResult.Failure != null)
                {
                    // Token无效/过期等带异常的失败
                    statsd?.Increment("api.auth.failure");
                }
                else if (authenticateResult.None)
                {
                    // 完全无Token的情况
                    statsd?.Increment("api.auth.no_token");
                }
            }
        }
    });

    app.UseMvc();
    // ...其他中间件
}

这个方案能覆盖所有返回401的场景,不管是认证中间件直接拦截的,还是[Authorize]触发的。

方案三:全局添加IAuthorizationFilter处理授权失败

如果还要统计权限不足(Token有效但无对应权限)的场景,可以添加一个全局授权过滤器:

public class AuthorizationStatsFilter : IAuthorizationFilter
{
    private readonly IStatsdClient _statsdClient;

    public AuthorizationStatsFilter(IStatsdClient statsdClient)
    {
        _statsdClient = statsdClient;
    }

    public void OnAuthorization(AuthorizationFilterContext context)
    {
        if (context.Result is UnauthorizedResult)
        {
            // 认证失败触发的401
            _statsdClient.Increment("api.auth.unauthorized");
        }
        else if (context.Result is ForbidResult)
        {
            // 权限不足触发的403
            _statsdClient.Increment("api.auth.forbidden");
        }
    }
}

然后在ConfigureServices里注册为全局过滤器:

services.AddMvc(options =>
{
    options.Filters.Add<AuthorizationStatsFilter>();
});

总结推荐

  • 只针对JWT认证场景:用方案一即可;
  • 需要覆盖所有认证类型:方案二更通用;
  • 要统计权限不足的情况:搭配方案三使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 06:43:44