如何记录未通过身份验证的ASP.NET Core WebAPI调用?
未认证/认证失败API调用的记录实现方案
因为ActionFilterAttribute的OnActionExecuting仅在认证通过后才会触发,未认证的请求根本走不到这个环节,所以得从更早的请求管道节点入手,以下是两种实用方案:
1. 自定义中间件(覆盖全场景)
中间件是请求进入ASP.NET Core管道的早期环节,能捕获所有到达服务器的请求,不管认证是否成功,适合记录所有未授权类请求(包括路由匹配失败、认证失败、权限不足等场景)。
实现步骤
- 新建中间件类,比如
UnauthorizedRequestLoggerMiddleware - 在
InvokeAsync方法中先记录请求基础信息,再传递请求到下一个中间件 - 后续检查响应状态码,针对
401(未认证)或403(权限不足)的请求补全记录
示例代码:
public class UnauthorizedRequestLoggerMiddleware { private readonly RequestDelegate _next; private readonly ILogger<UnauthorizedRequestLoggerMiddleware> _logger; public UnauthorizedRequestLoggerMiddleware(RequestDelegate next, ILogger<UnauthorizedRequestLoggerMiddleware> logger) { _next = next; _logger = logger; } public async Task InvokeAsync(HttpContext context) { // 提前记录请求核心信息 var requestPath = context.Request.Path; var requestMethod = context.Request.Method; var clientIp = context.Connection.RemoteIpAddress?.ToString(); // 允许后续环节重读请求体(如需记录参数) context.Request.EnableBuffering(); // 传递请求到下一个中间件 await _next(context); // 判定是否为未授权类响应 if (context.Response.StatusCode == StatusCodes.Status401Unauthorized || context.Response.StatusCode == StatusCodes.Status403Forbidden) { // 如需读取请求参数,可在此处读取context.Request.Body(记得重置流位置) _logger.LogWarning("未授权请求: 路径={Path}, 方法={Method}, 客户端IP={ClientIp}, 状态码={StatusCode}", requestPath, requestMethod, clientIp, context.Response.StatusCode); } } } // 扩展方法简化中间件注册 public static class UnauthorizedRequestLoggerMiddlewareExtensions { public static IApplicationBuilder UseUnauthorizedRequestLogger(this IApplicationBuilder builder) { return builder.UseMiddleware<UnauthorizedRequestLoggerMiddleware>(); } }
注册中间件
在Program.cs(或旧版Startup.cs)中,将该中间件注册在认证中间件之前,确保能捕获所有请求:
var app = builder.Build(); // 放在UseAuthentication之前 app.UseUnauthorizedRequestLogger(); app.UseAuthentication(); app.UseAuthorization(); // 其他中间件配置...
2. 利用认证事件(聚焦认证环节)
如果只关注认证过程中的失败场景,可以直接在对应认证方案的事件中处理,比如JWT认证的OnAuthenticationFailed、Cookie认证的对应事件。
示例(以JWT认证为例):
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { // 常规JWT配置... options.Events = new JwtBearerEvents { // 处理JWT认证失败的情况(比如token无效、过期) OnAuthenticationFailed = context => { var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<Program>>(); logger.LogError(context.Exception, "JWT认证失败: 路径={Path}, 方法={Method}", context.HttpContext.Request.Path, context.HttpContext.Request.Method); return Task.CompletedTask; }, // 处理认证通过但权限不足的情况 OnChallenge = context => { var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<Program>>(); logger.LogWarning("权限不足: 路径={Path}, 方法={Method}", context.HttpContext.Request.Path, context.HttpContext.Request.Method); return Task.CompletedTask; } }; });
这种方式更聚焦于认证环节的错误,适合只需要追踪认证相关失败的场景。
注意事项
- 若要读取请求体内容,必须先调用
context.Request.EnableBuffering(),否则后续环节无法再次读取请求体 - 中间件方式覆盖范围更广,能捕获所有未到达Action的请求;认证事件方式仅覆盖认证流程内的失败情况
内容的提问来源于stack exchange,提问作者Yan
相关产品推荐
相关产品推荐

