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

ASP.NET MVC中AJAX请求传递AntiForgeryToken失败如何解决?

ASP.NET MVC AJAX删除请求中AntiForgeryToken验证失败问题

问题场景

在ASP.NET MVC的Index视图中,列表每条数据都有删除用的ActionLink,URL格式为/Controller/Delete/id。点击链接弹出确认模态框后,通过AJAX发送POST请求到带[HttpPost]和[ValidateAntiForgeryToken]特性的控制器Delete方法,但始终报错:

缺少必需的防伪表单字段“__RequestVerificationToken”。

控制器Delete方法代码:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Delete(int id)
{
    try
    {
        Group g = db.Groups.Find(id);
        if (g != null)
        {
            db.Groups.Remove(g);
            db.SaveChanges();
            var url = Url.Action("IndexPartial");
            
            return Json(new
            {
                success = true,
                message = "删除成功",
                redirectUrl = url
            });
        }
        else
        {
            return Json(new
            {
                success = false,
                message = "记录未找到"
            });
        }
    }
    catch (Exception ex)
    {
        return Json(new
        {
            success = false,
            message = ex.Message.ToString()
        });
    }
}

视图已添加@Html.AntiForgeryToken(),AJAX请求代码:

$('#confirmActionBtn').on('click', function () {

        var token = $('[name="__RequestVerificationToken"]').val(); // 获取AntiForgeryToken值

        $.ajax({
            url: actionConfirmModal.attr("data-actionUrl"),
            type: 'POST',
            contentType: 'application/json',
            headers: {'RequestVerificationToken':token},
            success: function (response) {
                setupModal('result');
                if (response.success) {
                    if (response.redirectUrl != null) {
                        var targetPlaceHolder = actionConfirmModal.attr("data-targetPlaceHolder");
                        if (targetPlaceHolder != null) {
                            targetPlaceHolder.load(redirectUrl);
                        }
                        else {
                            window.location.href = redirectUrl;
                        }
                    }
                    else {
                        // 执行其他操作
                    }
                }
                else {
                    $('#resultMessage').text("错误 : " + response.message);
                }
            },
            error: function (xhr, status, error) {
                setupModal('result');
                $('#resultMessage').text("错误 : " + error);
            },
        });

    });

问题原因

默认情况下,ASP.NET MVC的[ValidateAntiForgeryToken]特性只会从表单字段或请求的Form集合中读取__RequestVerificationToken,而当前代码把Token放在请求Header里,并且设置了contentType: 'application/json',导致后端无法识别到Token。

解决方案

方案1:将Token放入请求Body中(推荐)

修改AJAX代码,把Token和ID一起作为JSON数据发送,同时保留contentType: 'application/json':

$('#confirmActionBtn').on('click', function () {
    var token = $('[name="__RequestVerificationToken"]').val();
    var actionUrl = actionConfirmModal.attr("data-actionUrl");
    var id = actionUrl.split('/').pop(); // 从URL中提取id

    $.ajax({
        url: actionUrl,
        type: 'POST',
        contentType: 'application/json',
        data: JSON.stringify({
            __RequestVerificationToken: token,
            id: id
        }),
        success: function (response) {
            setupModal('result');
            if (response.success) {
                if (response.redirectUrl != null) {
                    var targetPlaceHolder = actionConfirmModal.attr("data-targetPlaceHolder");
                    if (targetPlaceHolder != null) {
                        $(targetPlaceHolder).load(response.redirectUrl); // 修复原代码的变量引用错误
                    }
                    else {
                        window.location.href = response.redirectUrl;
                    }
                }
                else {
                    // 执行其他操作
                }
            }
            else {
                $('#resultMessage').text("错误 : " + response.message);
            }
        },
        error: function (xhr, status, error) {
            setupModal('result');
            $('#resultMessage').text("错误 : " + error);
        },
    });
});

方案2:自定义验证特性支持Header读取Token

如果不想修改前端,可以创建自定义的AntiForgeryToken验证特性,允许从Header中读取Token:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class ValidateAntiForgeryTokenFromHeaderAttribute : FilterAttribute, IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationContext filterContext)
    {
        var httpContext = filterContext.HttpContext;
        var token = httpContext.Request.Headers["RequestVerificationToken"];
        if (string.IsNullOrEmpty(token))
        {
            filterContext.Result = new HttpStatusCodeResult(HttpStatusCode.BadRequest, "缺少防伪令牌");
            return;
        }

        try
        {
            AntiForgery.Validate(httpContext.User.Identity.Name, token);
        }
        catch (AntiForgeryValidationException)
        {
            filterContext.Result = new HttpStatusCodeResult(HttpStatusCode.Forbidden, "防伪令牌验证失败");
        }
    }
}

然后将控制器上的[ValidateAntiForgeryToken]替换为[ValidateAntiForgeryTokenFromHeader]即可。

方案3:使用FormData格式发送请求

不设置contentType: 'application/json',改用FormData传递Token和ID:

$('#confirmActionBtn').on('click', function () {
    var token = $('[name="__RequestVerificationToken"]').val();
    var actionUrl = actionConfirmModal.attr("data-actionUrl");
    var id = actionUrl.split('/').pop();

    var formData = new FormData();
    formData.append('__RequestVerificationToken', token);
    formData.append('id', id);

    $.ajax({
        url: actionUrl,
        type: 'POST',
        data: formData,
        processData: false, // 必须设置,避免jQuery错误处理FormData
        contentType: false, // 必须设置,让浏览器自动生成正确的Content-Type
        success: function (response) {
            setupModal('result');
            if (response.success) {
                if (response.redirectUrl != null) {
                    var targetPlaceHolder = actionConfirmModal.attr("data-targetPlaceHolder");
                    if (targetPlaceHolder != null) {
                        $(targetPlaceHolder).load(response.redirectUrl);
                    }
                    else {
                        window.location.href = response.redirectUrl;
                    }
                }
                else {
                    // 执行其他操作
                }
            }
            else {
                $('#resultMessage').text("错误 : " + response.message);
            }
        },
        error: function (xhr, status, error) {
            setupModal('result');
            $('#resultMessage').text("错误 : " + error);
        },
    });
});

注意:原AJAX代码中targetPlaceHolder.load(redirectUrl)存在变量引用错误,需改为$(targetPlaceHolder).load(response.redirectUrl),因为redirectUrl是响应对象的属性而非全局变量。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 04:35:04