.NET Core 6中AuthorizationHandler读取请求Body时出现异常行为
问题分析与解决方案
核心原因:异步操作未等待
在MyCalendarChangeAuthorizationHandler的HandleRequirementAsync方法中,调用request.Body.CopyToAsync(memStream)时未使用await关键字,导致代码跳过异步复制操作直接执行后续读取逻辑。此时内存流还未接收到请求体内容,读取结果为空字符串,反序列化失败后触发context.Fail(),返回403。
由于异步操作的执行时机不确定,偶尔请求体较小会刚好完成复制,因此出现“相同请求有时成功有时失败”的随机现象。
次要问题:请求缓冲中间件顺序错误
你在Startup.cs中将启用请求缓冲的中间件放在了UseAuthorization之后:
app.UseAuthorization(); app.Use(next => context => { context.Request.EnableBuffering(); return next(context); });
授权中间件执行时,请求体尚未启用缓冲,若之前有其他组件读取过请求体,后续将无法再次读取,也会导致读取空内容的情况。
修复步骤
1. 修复异步操作等待问题
修改MyCalendarChangeAuthorizationHandler代码,给异步方法添加await:
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, MyCalendarChangeRequirement requirement) { MyDto my; var request = _httpContextAccessor.HttpContext.Request; request.EnableBuffering(); try { request.Body.Position = 0; using var memStream = new MemoryStream(); // 添加await等待复制完成 await request.Body.CopyToAsync(memStream); memStream.Position = 0; var body = new StreamReader(memStream).ReadToEnd(); _logger.LogInformation(body); var calendarChange = JsonConvert.DeserializeObject<CalendarChangesDto>(body); if (calendarChange == null || calendarChange.someId <= 0) { context.Fail(); _logger.LogWarning($"Message could not be parsed to {nameof(CalendarChangesDto)}"); request.Body.Position = 0; return Task.CompletedTask; } // 其余无关代码 } catch(Exception ex) { _logger.LogError(ex, "Error handling calendar change authorization"); context.Fail(); request.Body.Position = 0; return Task.CompletedTask; } }
2. 调整请求缓冲中间件顺序
在Startup.cs中,将启用请求缓冲的中间件移至UseAuthorization之前,确保授权处理时请求体可被多次读取:
app.UseRouting(); // 先启用请求缓冲 app.Use(next => context => { context.Request.EnableBuffering(); return next(context); }); app.UseAuthorization(); app.UseEndpoints(routes => { routes.MapHub<MyHub>("/myHub"); routes.MapControllers(); });
3. 额外优化建议
- 读取完请求体后,务必将
request.Body.Position重置为0,避免后续控制器的[FromBody]参数无法读取请求体。 - 添加异常捕获逻辑,防止反序列化过程中出现异常导致授权逻辑中断。
内容的提问来源于stack exchange,提问作者Cromm
相关产品推荐
相关产品推荐

