Le champ de formulaire anti-falsification «__RequestVerificationToken» n’est pas présent lors de l’utilisation de jQuery Ajax et de Html.AntiForgeryToken ()

J’ai implémenté l’équivalent Razor pour la solution décrite dans la réponse acceptée à cette question: Appels jQuery Ajax et Html.AntiForgeryToken () .

System.Web.Mvc.HttpAntiForgeryException (0x80004005): Le champ de formulaire anti-falsification requirejs “__RequestVerificationToken” n’est pas présent.

modifier

J’ai réussi à contourner le problème en faisant ceci:

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

Malheureusement, FormData () n’est pris en charge que dans les dernières versions du navigateur. Toute solution de contournement qui pourrait fonctionner avant que FormData () ne soit introduite?

edit Je me demande pourquoi ValidateAntiForgeryTokenAtsortingbute recherche AntyForgeryToken uniquement dans les données de formulaire et ne le recherche pas dans les valeurs de rout comme vous pouvez le voir ci-dessous dans le code des classes scellées AntiForgeryTokenStore et AntiForgeryWorker ?

 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) { ssortingng serializedToken = httpContext.Request.Form[this._config.FormFieldName]; if (ssortingng.IsNullOrEmpty(serializedToken)) return (AntiForgeryToken) null; else return this._serializer.Deserialize(serializedToken); } 

Eh bien, après en avoir creusé un peu plus, j’ai trouvé une solution intéressante à mon problème dans ce lien: Protection CSRF ASP.NET MVC Ajax avec jQuery 1.5

Pour autant que je comprenne la solution décrite dans la réponse choisie pour cette question: les appels jQuery Ajax et le Html.AntiForgeryToken () ne devraient pas fonctionner (cela a échoué pour moi).

Créer un antiforgerytoken:

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

Créez une fonction pour append le jeton à la demande ajax:

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

Vous pouvez ensuite l’utiliser comme ceci:

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

Lorsque vous appelez CallAjax() , d’où proviennent les data ? Je pose la question parce que, généralement, lorsque vos données proviennent d’un formulaire, votre jeton CSRF fait déjà partie du formulaire, généralement dans un champ masqué.

 
.... other form fields ....

Par conséquent, si toutes vos données proviennent d’un formulaire, vous devez simplement vous assurer que le jeton est une partie cachée de ce formulaire et qu’il doit automatiquement être inclus.

Si vos données proviennent d’un endroit autre qu’un formulaire, il est compréhensible que vous stockiez votre jeton quelque part et l’incluiez ensuite une fois les données assemblées. Mais vous pouvez envisager d’append le jeton aux données plutôt que de créer un nouvel object à partir du jeton, puis de lui append toutes les données.

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