使用 jQuery Ajax 和 Html.AntiForgeryToken() 时不存在防伪表单字段“__RequestVerificationToken”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16793516/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 17:48:24  来源:igfitidea点击:

anti-forgery form field "__RequestVerificationToken" is not present when using jQuery Ajax and the Html.AntiForgeryToken()

jqueryasp.net-mvc-4

提问by RonyK

I implemented the Razor equivalent for the solution described in the accepted answer for this Question: jQuery Ajax calls and the Html.AntiForgeryToken()But I kept getting the following exception:

我为这个问题的已接受答案中描述的解决方案实现了 Razor 等效项: jQuery Ajax 调用和 Html.AntiForgeryToken()但我一直收到以下异常:

System.Web.Mvc.HttpAntiForgeryException (0x80004005): The required anti-forgery form field "__RequestVerificationToken" is not present.

System.Web.Mvc.HttpAntiForgeryException (0x80004005):所需的防伪表单字段“__RequestVerificationToken”不存在。

edit

编辑

I manged to workaround it doing this:

我设法解决它这样做:

function AddAntiForgeryToken(data) {
    data.append('__RequestVerificationToken',$('#__AjaxAntiForgeryForm input[name=__RequestVerificationToken]').val());
    return data;
};

function CallAjax(url, type, data, success, error) {

    var ajaxOptions = { url: url, type: type, contentType: 'application/json'};

    if (type == 'POST') {
        var fd = new window.FormData();
        fd = AddAntiForgeryToken(fd);
        $.each(data, function (i, n) {
            fd.append(i,n);
        });
        data = fd;
        ajaxOptions.processData = false;
        ajaxOptions.contentType = false;
    }

    ajaxOptions.data = data;

    if (success) ajaxOptions.success = success;

    //If there is a custom error handler nullify the general statusCode setting.
    if (error) {
        ajaxOptions.error = error;
        ajaxOptions.statusCode = null;
    };

    $.ajax(ajaxOptions);
}

But unfortunately FormData() is only supported in latest browser versions. Any workaround that could work before FormData() as introduced?

但不幸的是 FormData() 仅在最新的浏览器版本中受支持。任何可以在引入 FormData() 之前工作的解决方法?

editI wonder why the ValidateAntiForgeryTokenAttributelooks for the AntyForgeryToken only in the Form data, and doesn't look for it in the rout values as you can see below in the code of the sealed classes AntiForgeryTokenStoreand AntiForgeryWorker?

编辑我想知道为什么ValidateAntiForgeryTokenAttribute只在 Form 数据中查找 AntyForgeryToken,而不在路由值中查找它,正如您在下面密封类AntiForgeryTokenStoreAntiForgeryWorker的代码中看到的那样?

public void Validate(HttpContextBase httpContext)
{
  this.CheckSSLConfig(httpContext);
  AntiForgeryToken cookieToken = this._tokenStore.GetCookieToken(httpContext);
  AntiForgeryToken formToken = this._tokenStore.GetFormToken(httpContext);
  this._validator.ValidateTokens(httpContext, AntiForgeryWorker.ExtractIdentity(httpContext), cookieToken, formToken);
}


public AntiForgeryToken GetFormToken(HttpContextBase httpContext)
{
  string serializedToken = httpContext.Request.Form[this._config.FormFieldName];
  if (string.IsNullOrEmpty(serializedToken))
    return (AntiForgeryToken) null;
  else
    return this._serializer.Deserialize(serializedToken);
}

采纳答案by RonyK

Well, after digging some more I found a nice solution to my problem in this link: ASP.NET MVC Ajax CSRF Protection With jQuery 1.5

好吧,在挖掘了更多之后,我在此链接中找到了一个很好的解决我的问题的方法: ASP.NET MVC Ajax CSRF Protection With jQuery 1.5

As far as I understand the solution described in the chosen answer for this question: jQuery Ajax calls and the Html.AntiForgeryToken(), shouldn't work (indeed it failed for me).

据我了解在这个问题的选择答案中描述的解决方案:jQuery Ajax 调用和 Html.AntiForgeryToken(),不应该工作(实际上它对我来说失败了)。

回答by Krishna

Create antiforgerytoken:

创建防伪令牌:

@using (Html.BeginForm()) {
    @Html.AntiForgeryToken()
    <input ...>
}

Create a function to add the token to the ajax request :

创建一个函数来将令牌添加到 ajax 请求中:

function addRequestVerificationToken(data) {
    data.__RequestVerificationToken=$('input[name=__RequestVerificationToken]').val();
    return data;
};

You can then use it like this:

然后你可以像这样使用它:

$.ajax({
   type: "POST",
   url: '@Url.Action("MyMethod", "MyController", new {area = "MyArea"})',
   dataType: "json",
   traditional: true,
   data: addRequestVerificationToken( { "id": "12345678" } );
})
.done(function(result) {
   if (result) {
       // Do something
   } else {
       // Log or show an error message
   }
   return false;
});

回答by slashingweapon

When you call CallAjax(), where is datacoming from? I ask because, usually when your data comes from a form then your CSRF token is already part of the form, typically in a hidden field.

当你打电话时CallAjax()data来自哪里?我问是因为,通常当您的数据来自表单时,您的 CSRF 令牌已经是表单的一部分,通常位于隐藏字段中。

<form action="yourPage.html" method="POST">
    <input type="hidden" name="__RequestVerificationToken" value="......"/>
    .... other form fields ....
</form>

So if your data is all coming from a form, then you should just make sure that the token is a hidden part of that form and the token should automatically be included.

因此,如果您的数据全部来自表单,那么您应该确保令牌是该表单的隐藏部分,并且应自动包含该令牌。

If your data is coming from somewhere other than a form, then it is understandable that you would stash your token somewhere and then include it after the data has been assembled. But you might consider adding the token to the data, rather than building a new object from the token and then adding all the data to it.

如果您的数据来自表单以外的其他地方,那么您可以将您的令牌存放在某处,然后在组装数据后将其包含在内,这是可以理解的。但是您可能会考虑将令牌添加到数据中,而不是从令牌构建一个新对象,然后将所有数据添加到其中。

if (type == 'POST') {
    data._RequestVerificationToken = $("input[name='__RequestVerificationToken']").val();
    ajaxOptions.processData = false;
    ajaxOptions.contentType = false;
}