【问题标题】:Can't access to action method from JQuery if [AntiForgeryToken] is enabled如果启用了 [AntiForgeryToken],则无法从 JQuery 访问操作方法
【发布时间】:2016-07-11 04:31:10
【问题描述】:

我有一个可以正常工作的 JQuery 函数,但是如果我在 Action Method 上启用 [AntiForgerToken],则 JQuery 函数无法访问 Action Method,在我启用 AntiForgeryToken 的位置上,我还有其他 sn-p:

@using (Html.BeginForm("InsertStudent","Students",FormMethod.Post, new { @id="myform"}))
{
    @Html.AntiForgeryToken()

不管view里面的@Html.AntiForgeryToken()是否开启,JQuery函数都很好用,问题出在Action Method上……

为什么会这样?我错过了什么??我读过在 Post Action 方法上启用 [AntiForgeryToken] 对于安全性非常重要,所以我认为应用程序应该在 Action Method 和 View 的两个地方都启用它。

jQuery 函数:

function InsertShowStudents() {
    var counter = 0;
    $.ajax({        
        type:"post",
        url: "/Students/InsertStudent/",
        data: { Name: $("#Name").val(), LastName: $("#LastName").val(), Age: $("#Age").val() }
    }).done(function (result) {
        if (counter==0) {
        GetStudents();
        CounterStudents();
            counter = 1;
        }
        else {
            $("#tableJQuery").append("<tr>"+"<td>"+result.Name+"</td>"+"<td>"+result.LastName+"</td>"+"<td>"+result.Age+"</td>"+"</tr>")
        }
        //clear the form
       $("#myform")[0].reset();
    }).error(function () {
        $("#divGetStudents").html("An error occurred")
    })
}

动作方法:

 [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult InsertStudent(Student student)
        {
            if (ModelState.IsValid)
            {
                db.Students.Add(student);
                db.SaveChanges();
                //ModelState.Clear();
                return RedirectToAction("InsertStudent");
            }
            return View(student);
        }

表格的列:

@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.Name)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.LastName)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Age)
        </td>
      @* <td style="display:none" class="tdStudentID">@Html.DisplayFor(modelItem => item.StudentID)</td>    *@  
        <td>
            <img src="~/images/deleteIcon.png" width="20" height="20" class="imgJQuery" data-id="@item.StudentID" />
        </td>
       <td>
           @Html.ActionLink("Details","Details", new { id=item.StudentID})
       </td>
    </tr>
}

【问题讨论】:

  • 您没有在 ajax 数据中传递令牌的值。如果您只使用data: $('#myform').serialize(), 最简单,它将序列化包括令牌在内的所有表单控件。但是在你的 POST 方法中使用RedirectToAction() 是没有意义的——ajax 调用永远不会重定向。
  • @StephenMuecke 它现在可以工作了 :),您是否要发布答案以便我可以给您指出,或者如果我这样做,您更喜欢吗?
  • 给我 20 分钟,我会添加这个和另一个替代方案
  • 类似方式:stackoverflow.com/questions/14473597/…。可以使用var token = $('#myform input[name=__RequestVerificationToken]').val();获取验证令牌,并将其传递到序列化数据部分。
  • @StephenMuecke 好的,我会更改Action Method 并删除RedirectToAction() 然后,没想到ajax 永远不会重定向

标签: c# jquery asp.net-mvc razor data-annotations


【解决方案1】:

您没有在 ajax 调用中传递令牌的值,因此会引发异常。您可以使用

获取令牌的值
var token = $('[name=__RequestVerificationToken]').val();

并修改您的 ajax 调用以包含它使用

data: { __RequestVerificationToken: token, Name: $("#Name").val(), LastName: $("#LastName").val(), Age: $("#Age").val() }

但是,序列化包含令牌的表单会更容易

$.ajax({        
    type:"post",
    url: '@Url.Action("InsertStudent", "Students")', // don't hardcode your url's
    data: $('#myform').serialize(),
}).done(function (result) {

旁注:Ajax 调用永远不会重定向(ajax 的全部意义在于保持在同一页面上),因此在 InsertStudent() 中包含 return RedirectToAction("InsertStudent"); 将不起作用。另外,你返回的html,所以.done()回调中的$("#tableJQuery").append()代码会失败。

您似乎有一个表单来添加新的Student,因此您的方法只需要返回一个JsonResult,表示成功或其他情况,如果成功,则可以根据值向表中添加新行以表格为例

}).done(function (result) {
    if (result) {
        var row = $('<tr></tr>');
        row.append($('<td></td>').text($("#Name").val()));
        ... // add other cells
        $("#tableJQuery").append(row);
        //clear the form
        $("#myform")[0].reset();
    } else {
        // Oops something went wrong
    }
})

【讨论】:

  • 非常好,我使用的是外部 js 文件,所以我在 View 中声明了一个隐藏的输入文本,其中包含 Url.Action 的信息,并从外部 js 文件中的 ajax 引用它,即效果很好。我也修改了动作方法,无论成功与否,我都会返回 Json。
  • 唯一的事情是我在我的表中添加了一个带有 img 元素的新列,因此当单击该 img 元素将被删除(使用 ajax 实现)时,我还添加了其他名为 Details 的列学生的详细信息,它调用详细信息操作方法,所以我不确定我是否可以使用 ajax 添加一行数据、img 的功能和详细信息超链接,你建议我调用 GetStudents()直接作用?
  • 你应该使用data-*属性而不是隐藏输入。例如,在触发脚本的按钮中,您可以使用添加data-url="@Url.Action(....)",然后使用var url = $(this).data('url'); 检索它。但是在您的情况下,您已经在使用Html.BeginForm() 生成的&lt;form&gt; 标记中拥有它,因此您可以使用url: $('#myform').attr('action');
  • 您可以轻松地创建包含图像和链接的新行的 html。 InsertStudent 方法只需要返回 json,包括您插入的 Student 的新 ID(例如 return Json(new { id = student.StudentID });),然后在 ajax 中 - row.append($('&lt;td&gt;&lt;/td&gt;').append($('&lt;img&gt;').attr('scr', '....').data('id', response.id)));) - 没有理由通过使多次调用服务器并重新生成整个表
  • 另一种选择是返回新Student 的部分视图,它只是Student 的单个&lt;tr&gt; 元素,然后将其附加到现有表中。
猜你喜欢
  • 2020-10-13
  • 1970-01-01
  • 2017-04-22
  • 2014-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-28
  • 2012-11-18
相关资源
最近更新 更多