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

我为这个问题的接受答案中描述的解决方案实现了Razor等价物: jQuery Ajax调用和Html.AntiForgeryToken()但是我一直得到以下exception:

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

编辑

我这样做是为了解决这个问题:

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); } 

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

编辑我想知道为什么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); } 

好了,经过深入挖掘后,我在这个链接中找到了一个很好的解决方案: ASP.NET MVC Ajax CSRF保护使用jQuery 1.5

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

创建antiforgerytoken:

 @using (Html.BeginForm()) { @Html.AntiForgeryToken()  } 

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

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

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

 $.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; }); 

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

 
.... other form fields ....

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

如果您的数据来自表单以外的某个地方,那么您可以将您的令牌存储在某个地方然后在数据汇编后包含它是可以理解的。 但您可以考虑将令牌添加到数据中,而不是从令牌构建新对象,然后将所有数据添加到其中。

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