ASP.NET Core JWT认证出现重复响应问题求助
解决ASP.NET Core JWT认证中的重复响应问题
问题根源
重复响应的核心原因是**OnAuthenticationFailed事件处理完响应后未终止后续流程,导致OnChallenge事件再次写入相同的响应内容**:
- 当Token篡改触发
SecurityTokenInvalidSignatureException或SecurityTokenMalformedException时,OnAuthenticationFailed中已经写入了498状态码的响应内容,但未调用ctx.HandleResponse(),认证流程会继续触发OnChallenge事件。 OnChallenge中检测到之前添加的X-TOKEN-TAMPERED响应头,再次写入相同的TokenTamperedResponse,最终导致响应体中出现两份重复的JSON。
修复方案
修改OnAuthenticationFailed事件处理逻辑,在写入响应后调用ctx.HandleResponse(),终止后续认证流程,避免OnChallenge重复处理:
修改后的JWT认证事件代码
options.Events = new JwtBearerEvents { OnMessageReceived = ctx => { var actionName = ctx.Request.RouteValues["action"]?.ToString() ?? String.Empty; if (ctx.Request.Cookies.ContainsKey(CommonConstants.TokenName) && !actionName.Equals("Authenticate", StringComparison.OrdinalIgnoreCase) && !actionName.Equals("RenewToken", StringComparison.OrdinalIgnoreCase)) { ctx.Token = ctx.Request.Cookies[CommonConstants.TokenName]; } return Task.CompletedTask; }, OnAuthenticationFailed = ctx => { if (!ctx.Response.HasStarted) { if (ctx.Exception is SecurityTokenInvalidSignatureException || ctx.Exception is SecurityTokenMalformedException) { ctx.Response.Headers.Add("X-TOKEN-TAMPERED", "true"); ctx.Response.StatusCode = 498; ctx.Response.ContentType = "application/json"; var tamperedPayload = new TokenTamperedResponse(); var tamperedMessage = JsonConvert.SerializeObject(tamperedPayload); // 写入响应后终止后续流程,避免触发OnChallenge ctx.HandleResponse(); return ctx.Response.WriteAsync(tamperedMessage); } else if (ctx.Exception is SecurityTokenExpiredException) { ctx.Response.Headers.Add("IS-TOKEN-EXPIRED", "true"); ctx.Response.StatusCode = StatusCodes.Status401Unauthorized; ctx.Response.ContentType = "application/json"; var payload = new UnAuthorizedResponse("Token Expired"); var errorMessage = JsonConvert.SerializeObject(payload); // 终止后续流程 ctx.HandleResponse(); return ctx.Response.WriteAsync(errorMessage); } } return Task.CompletedTask; }, OnChallenge = ctx => { if (!ctx.Response.HasStarted) { ctx.HandleResponse(); // 仅处理无异常的未授权场景(如请求中无Token) ctx.Response.StatusCode = StatusCodes.Status401Unauthorized; ctx.Response.ContentType = "application/json"; var payload = new UnAuthorizedResponse(); var errorMessage = JsonConvert.SerializeObject(payload); return ctx.Response.WriteAsync(errorMessage); } return Task.CompletedTask; }, OnTokenValidated = async ctx => { await Task.CompletedTask; } };
优化说明
OnAuthenticationFailed负责处理异常类的未授权场景(Token篡改、过期),通过ctx.HandleResponse()终止流程,避免进入OnChallenge。OnChallenge仅处理无异常的未授权场景(如请求中没有Token),职责划分更清晰,彻底避免重复响应。- 日志中间件逻辑无需修改,重复响应的根源是认证事件的重复写入,而非中间件问题。
内容的提问来源于stack exchange,提问作者Deepak Verma
相关产品推荐
相关产品推荐

