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

C# Razor Pages中无表单AJAX POST与AntiForgery的正确处理

Razor Pages 无表单AJAX POST的防伪造令牌解决方案

问题场景

在Razor Pages页面实现消息列表展示,通过JavaScript的Edit(id)方法异步加载编辑HTML片段并注入页面;使用Save(id)方法通过AJAX POST提交修改时,因未使用<form>标签,ASP.NET Core内置的防伪造令牌框架未自动生成验证令牌,导致请求触发404错误。同时需要支持并行编辑多条消息,不想通过[IgnoreAntiforgeryToken]注解规避验证(存在CSRF安全风险),也不确定是否需要为每条编辑的消息生成独立令牌。

解决方案

  1. 在主视图底部添加@Html.AntiForgeryToken()生成全局可用的防伪造令牌
  2. 修改Save函数,通过请求头携带该令牌完成验证
  3. 移除后台PageModel上的[IgnoreAntiforgeryToken]注解
  4. 该令牌可重复用于多条消息的编辑提交,无异常

原主视图(View.cshtml)

@foreach (var item in Model.Messages) {
    <div id="message_@item.Id">
        <label class="form-label">@item.Type:</label>
        @{
            var result = Markdown.ToHtml(item.Message, pipeline);
            @Html.Raw(result)
        }
    </div>
    <div class="mb-3 text-end">
        <a href="#" onclick="Edit(@item.Id)">✏</a>
        <a href="#" onclick="Delete(@item.Id)">❌</a>
    </div>
}

@section Scripts {
    <script>
        function Edit(messageId) {
            $.get(
                "/Messages/_EditMessage?messageId=" + messageId,
                function (str) {
                    $('#message_' + messageId).html(str);
                }
            );
        }
        function Save(messageId) {
            $.post(
                "/Messages/_EditMessage?messageId=" + messageId,
                { NewMessage: $('#NewMessage_' + messageId).val() },
                function (str) {
                    $('#message_' + messageId).html(str);
                }
            );
        }
    </script>
}

编辑部分视图(_EditMessage.cshtml)

@if (Model.Edit) {
    <div class="mb-3">
        <label class="form-label">@Model.Message.Type</label>
        <textarea class="form-control" id="NewMessage_@Model.Message.Id" rows="@(Model.Message.Message.Count(c => c == '\n') + 1)">@Model.Message.Message</textarea>
    </div>
    <div>
        <button class="btn btn-outline-success" onclick="Save(@Model.Message.Id)">Save</button>
    </div>
}
else {
    var result = Markdown.ToHtml(Model.Message.Message, pipeline);

    <label class="form-label">@Model.Message.Type:</label>
    @Html.Raw(result)
}

原后台PageModel(_EditMessage.cshtml.cs)

[IgnoreAntiforgeryToken]
public class _EditMessageModel : PageModel
{
    public TextMessage Message { get; set; } = null!;
    public bool Edit { get; set; }

    [BindProperty] public string NewMessage { get; set; } = string.Empty;

    public IActionResult OnGet(int messageId) {
        var message = MessageManager.Messages.FirstOrDefault(m => m.Id == messageId);
        if (message is null)
            return NotFound(messageId);

        Message = message;
        Edit = true;

        return Page();
    }

    public IActionResult OnPost(int messageId) {
        var message = MessageManager.Messages.FirstOrDefault(m => m.Id == messageId);
        if (message is null)
            return NotFound(messageId);

        Message = message;
        Message.Message = NewMessage;
        Edit = false;

        return Page();
    }
}

修正内容

  1. 在主视图(View.cshtml)的末尾添加防伪造令牌:
@Html.AntiForgeryToken()
  1. 修改Save函数为以下代码:
function Save(messageId) {
    $.ajax({
        type: "POST",
        headers: { "RequestVerificationToken": $('input[name="__RequestVerificationToken"]').val() },
        url: "/Messages/_EditMessage?messageId=" + messageId,
        data: { NewMessage: $('#NewMessage_' + messageId).val() }
    }).done(function(response){
        $('#message_' + messageId).html(response);
    });
}
  1. 移除后台PageModel上的[IgnoreAntiforgeryToken]注解,修正后的后台代码:
public class _EditMessageModel : PageModel
{
    public TextMessage Message { get; set; } = null!;
    public bool Edit { get; set; }

    [BindProperty] public string NewMessage { get; set; } = string.Empty;

    public IActionResult OnGet(int messageId) {
        var message = MessageManager.Messages.FirstOrDefault(m => m.Id == messageId);
        if (message is null)
            return NotFound(messageId);

        Message = message;
        Edit = true;

        return Page();
    }

    public IActionResult OnPost(int messageId) {
        var message = MessageManager.Messages.FirstOrDefault(m => m.Id == messageId);
        if (message is null)
            return NotFound(messageId);

        Message = message;
        Message.Message = NewMessage;
        Edit = false;

        return Page();
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 10:18:10