80 votes

Comment puis-je fournir un AntiForgeryToken lors de la publication de données JSON avec $ .ajax?

Je suis à l'aide du code ci-dessous de ce post:

Je vais d'abord remplir un tableau de variables avec les valeurs correctes pour l'action du contrôleur. À l'aide du code ci-dessous je pense qu'il devrait être très straigtforward par le simple ajout de la ligne suivante dans le code javascript:

data["__RequestVerificationToken"] = $('[name=__RequestVerificationToken]').val();

L' <%= Html.AntiForgeryToken() %> est à sa place et que l'action a un [ValidateAntiForgeryToken]

Mais mon contrôleur de l'action ne cesse de dire: "non Valide faux jeton"

Ce que je fais mal ici?

Code

data["fiscalyear"] = fiscalyear;
data["subgeography"] = $(list).parent().find('input[name=subGeography]').val();
data["territories"] = new Array();

$(items).each(function() {
    data["territories"].push($(this).find('input[name=territory]').val());
});

    if (url != null) {
        $.ajax(
        {
            dataType: 'JSON',
            contentType: 'application/json; charset=utf-8',
            url: url,
            type: 'POST',
            context: document.body,
            data: JSON.stringify(data),
            success: function() { refresh(); }
        });
    }

70voto

Ken Q Points 31

Vous n'avez pas besoin de la solution ValidationHttpRequestWrapper depuis MVC 4. Selon ce lien .

  1. Placez le jeton dans les en-têtes.
  2. Créez un filtre.
  3. Mettez l'attribut sur votre méthode.

Voici ma solution:

 var token = $('input[name="__RequestVerificationToken"]').val();
var headers = {};
headers['__RequestVerificationToken'] = token;
$.ajax({
    type: 'POST',
    url: '/MyTestMethod',
    contentType: 'application/json; charset=utf-8',
    headers: headers,
    data: JSON.stringify({
        Test: 'test'
    }),
    dataType: "json",
    success: function () {},
    error: function (xhr) {}
});


[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class ValidateJsonAntiForgeryTokenAttribute : FilterAttribute, IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationContext filterContext)
    {
        if (filterContext == null)
        {
            throw new ArgumentNullException("filterContext");
        }

        var httpContext = filterContext.HttpContext;
        var cookie = httpContext.Request.Cookies[AntiForgeryConfig.CookieName];
        AntiForgery.Validate(cookie != null ? cookie.Value : null, httpContext.Request.Headers["__RequestVerificationToken"]);
    }
}


[HttpPost]
[AllowAnonymous]
[ValidateJsonAntiForgeryToken]
public async Task<JsonResult> MyTestMethod(string Test)
{
    return Json(true);
}
 

50voto

Darin Dimitrov Points 528142

Ce qui est faux est que l'action du controller qui est censé s'occuper de cette demande, et qui est marqué par l' [ValidateAntiForgeryToken] attend un paramètre appelé __RequestVerificationToken pour être Affiché avec la demande.

Il n'y a pas de paramètre Affiché tant que vous utilisez JSON.stringify(data) qui convertit votre forme à sa représentation JSON et si l'exception est levée.

Je vois donc deux solutions possibles ici:

Numéro 1: Utilisez x-www-form-urlencoded au lieu de JSON pour l'envoi de votre demande de paramètres:

data["__RequestVerificationToken"] = $('[name=__RequestVerificationToken]').val();
data["fiscalyear"] = fiscalyear;
// ... other data if necessary

$.ajax({
    url: url,
    type: 'POST',
    context: document.body,
    data: data,
    success: function() { refresh(); }
});

Numéro 2: Séparer la demande en deux paramètres:

data["fiscalyear"] = fiscalyear;
// ... other data if necessary
var token = $('[name=__RequestVerificationToken]').val();

$.ajax({
    url: url,
    type: 'POST',
    context: document.body,
    data: { __RequestVerificationToken: token, jsonRequest: JSON.stringify(data) },
    success: function() { refresh(); }
});

Donc dans tous les cas, vous avez besoin d'afficher le __RequestVerificationToken de la valeur.

10voto

360Airwalk Points 1319

je viens de la mise en œuvre de ce réel problème dans mon projet en cours. je l'ai fait pour tous ajax-Postes que nécessaire à un utilisateur authentifié.

Tout d'abord, j'ai décidé d'accrocher mes appels ajax jquery donc je n'ai pas à me répéter trop souvent. ce bout de code javascript s'assure que tous les ajax (post) appels d'ajouter ma validation de la demande de jeton à la demande. Remarque: le nom de __RequestVerificationToken est utilisé par l' .Net framework afin que je puisse utiliser la norme Anti-CSRF fonctions comme indiqué ci-dessous.

$(document).ready(function () {
    securityToken = $('[name=__RequestVerificationToken]').val();
    $('body').bind('ajaxSend', function (elm, xhr, s) {
        if (s.type == 'POST' && typeof securityToken != 'undefined') {
            if (s.data.length > 0) {
                s.data += "&__RequestVerificationToken=" + encodeURIComponent(securityToken);
            }
            else {
                s.data = "__RequestVerificationToken=" + encodeURIComponent(securityToken);
            }
        }
    });
});

Dans votre point de Vue où vous en avez besoin le jeton à la disposition du javascript ci-dessus suffit d'utiliser le commun HTML-Helper. Vous pouvez ajouter ce code où vous le voulez. Je l'ai placé à l'intérieur d'un if(Request.IsAuthenticated):

@Html.AntiForgeryToken() // you can provide a string as salt when needed which needs to match the one on the controller

Dans votre contrôleur de simplement utiliser la norme ASP.Net MVC Anti-CSRF mécanisme. J'ai fait comme ça (même si j'ai effectivement utilisé le Sel).

[HttpPost]
[Authorize]
[ValidateAntiForgeryToken]
public JsonResult SomeMethod(string param)
{
    // do something
    return Json(true);
}

Avec Firebug ou un outil similaire, vous pouvez facilement voir comment votre POST demandes ont maintenant un __RequestVerificationToken paramètre ajouté.

5voto

Antoine Leclair Points 5818

Vous n'aurez jamais à valider un AntiForgeryToken lorsque vous recevez du JSON publié.

La raison en est que AntiForgeryToken a été créé pour empêcher CSRF. Étant donné que vous ne pouvez pas publier de données AJAX sur un autre hôte et que les formulaires HTML ne peuvent pas soumettre de code JSON en tant que corps de la demande, vous n'avez pas à protéger votre application contre le format JSON publié.

5voto

TWith2Sugars Points 2723

Je tiens le jeton dans mon objet JSON et j'ai fini par la modification de la ValidateAntiForgeryToken classe pour vérifier l' InputStream de la Demande de l'objet lors de la poste est en json. J'ai écrit un billet de blog à ce sujet, j'espère que vous pourriez trouver utile.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X