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

ASP.NET Core JWT认证出现重复响应问题求助

解决ASP.NET Core JWT认证中的重复响应问题

问题根源

重复响应的核心原因是**OnAuthenticationFailed事件处理完响应后未终止后续流程,导致OnChallenge事件再次写入相同的响应内容**:

  1. 当Token篡改触发SecurityTokenInvalidSignatureException或SecurityTokenMalformedException时,OnAuthenticationFailed中已经写入了498状态码的响应内容,但未调用ctx.HandleResponse(),认证流程会继续触发OnChallenge事件。
  2. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 18:13:15