web-dev-qa-db-fra.com

"Jeton CSRF manquant ou incorrect" tout en post paramètre via AJAX à Django

J'essaie de poster un paramètre comme 

 jQuery.ajax(
        {
            'type': 'POST',
            'url': url,
            'contentType': 'application/json',
            'data': "{content:'xxx'}",
            'dataType': 'json',
            'success': rateReviewResult 
        }
    );

Cependant, Django a retourné Forbidden 403. CSRF verification failed. Request aborted. J'utilise 'Django.middleware.csrf.CsrfViewMiddleware' et je ne trouve pas comment je peux prévenir ce problème sans compromettre la sécurité.

52
brsbilgic

Vous pouvez faire une demande de post AJAX de deux manières différentes:

  1. Pour indiquer à votre vue de ne pas vérifier le jeton csrf. Cela peut être fait en utilisant decorator @csrf_exempt, comme ceci:

    from Django.views.decorators.csrf import csrf_exempt
    
    @csrf_exempt
    def your_view_name(request):
        ...
    
  2. Pour incorporer un jeton csrf dans chaque demande AJAX, cela peut être pour jQuery

    $(function () {
        $.ajaxSetup({
            headers: { "X-CSRFToken": getCookie("csrftoken") }
        });
    });
    

    Où la fonction getCookie récupère le jeton csrf à partir des cookies. J'utilise l'implémentation suivante:

    function getCookie(c_name)
    {
        if (document.cookie.length > 0)
        {
            c_start = document.cookie.indexOf(c_name + "=");
            if (c_start != -1)
            {
                c_start = c_start + c_name.length + 1;
                c_end = document.cookie.indexOf(";", c_start);
                if (c_end == -1) c_end = document.cookie.length;
                return unescape(document.cookie.substring(c_start,c_end));
            }
        }
        return "";
     }
    

    En outre, jQuery a un plugin pour accéder aux cookies, quelque chose comme ça:

    // set cookie
    $.cookie('cookiename', 'cookievalue');<br>
    // read cookie
    var myCookie = $.cookie('cookiename');<br>
    // delete cookie
    $.cookie('cookiename', null);
    
81
sigurd

Le moyen le plus simple que j'ai trouvé consiste à inclure la valeur {{csrf_token}} dans les données:

jQuery.ajax(
    {
        'type': 'POST',
        'url': url,
        'contentType': 'application/json',
        'data': {
            'content': 'xxx',
            'csrfmiddlewaretoken': '{{ csrf_token }}',
        },
        'dataType': 'json',
        'success': rateReviewResult 
    }
);
34
jerrykan

Il m'a fallu un certain temps pour comprendre quoi faire avec le code que Daniel a posté. Mais en réalité, tout ce que vous avez à faire est de le coller au début du fichier javascript. 

Pour moi, la meilleure solution à ce jour est:

  1. Créer un fichier csrf.js

  2. Coller le code dans le fichier csrf.js

  3. Référencez le code dans le modèle dont vous avez besoin

    <script type="text/javascript" src="{{ STATIC_PREFIX }}js/csrf.js"></script>
    

Notez que STATIC_PREFIX/js/csrf.js pointe vers mon fichier. En fait, je charge la variable STATIC_PREFIX avec {% get_static_prefix as STATIC_PREFIX %}.


Astuce avancée: si vous utilisez des modèles et que vous avez une extension telle que base.html, vous pouvez simplement référencer le script à partir de là et vous n'avez plus à vous soucier de vos fichiers. Autant que je sache, cela ne devrait pas non plus représenter un problème de sécurité.

23
toto_tico

Simple et court

$.ajaxSetup({
  headers: { "X-CSRFToken": '{{csrf_token}}' }
});

OR

function csrfSafeMethod(method) {
  // these HTTP methods do not require CSRF protection
  return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
  beforeSend: function(xhr, settings) {
    if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
      xhr.setRequestHeader("X-CSRFToken", '{{csrf_token}}');
    }
  }
});

docs

8
Khaino

J'ai eu le même problème hier et je pensais que cela aiderait les gens s'il y avait un moyen simple de le gérer. J'ai donc écrit un plugin jQuery pour cela: jquery.djangocsrf . Au lieu d’ajouter le jeton CSRF à chaque requête, il s’associe à l’événement AjaxSend jQuery et ajoute le cookie client dans un en-tête.

Voici comment l'utiliser:

1- l'inclure:

<script src="path/to/jquery.js"></script>
<script src="path/to/jquery.cookie.js"></script>
<script src="path/to/jquery.djangocsrf.js"></script>

2- l'activer dans votre code:

$.djangocsrf( "enable" );

Django ajoute toujours le jeton dans un cookie si votre modèle utilise {% csrf_token %}. Pour vous assurer qu'il l'ajoute toujours, même si vous n'utilisez pas la balise spéciale dans votre modèle, utilisez le décorateur @ensure_csrf_cookie:

from Django.views.decorators.csrf import ensure_csrf_cookie

@ensure_csrf_cookie
def my_view(request):
    return render(request, 'mytemplate.html')

Remarque: j’utilise Django 1.6.2.

4
bfontaine

Merci à tous pour toutes les réponses. J'utilise Django 1.5.1. Je suis un peu en retard à la fête, mais voilà.

J'ai trouvé le lien vers le projet Django très utile, mais je ne voulais pas vraiment avoir à inclure le code JavaScript supplémentaire à chaque fois que je voulais passer un appel à Ajax.

J'aime la réponse de Jerrykan, car elle est très succincte et n’ajoute qu’une ligne à un appel Ajax par ailleurs normal. En réponse aux commentaires ci-dessous concernant les situations dans lesquelles les balises de modèle Django sont indisponibles, pourquoi ne pas charger csrfmiddlewaretoken à partir du DOM?

var token = $('input[name="csrfmiddlewaretoken"]').prop('value');
jQuery.ajax({
    type: 'POST',
    url: url,
    data: { 'csrfmiddlewaretoken': token },
    dataType: 'json',
    success: function(data) { console.log('Yippee! ' + data); } 
});

EDIT Mars 2016

Mon approche de cette question au cours des dernières années a changé. J'ajoute le code ci-dessous (à partir de Django docs ) à un fichier main.js et le charge sur chaque page. Une fois cela fait, vous ne devriez plus avoir à vous soucier du jeton CSRF avec ajax.

function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie != '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) == (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}
var csrftoken = getCookie('csrftoken');

4
jbiz

Inclure l'en-tête x-csrftoken dans la demande:

var token = $('input[name="csrfmiddlewaretoken"]').prop('value');
jQuery.ajax({
    type: 'POST',
    url: url,
    beforeSend : function(jqXHR, settings) {
        jqXHR.setRequestHeader("x-csrftoken", get_the_csrf_token_from_cookie());
    },
    data: data,
    dataType: 'json',

});
3
Hasan Ramezani

En l'absence d'une réponse directe, il vous suffit d'ajouter l'en-tête X-CSRFToken à la demande ajax qui se trouve dans le cookie csrftoken. JQuery ne fait pas de cookies (pour une raison quelconque) sans un plugin so:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>

et le changement de code minimal est:

$.ajax({
  headers: { "X-CSRFToken": $.cookie("csrftoken") },
  ...
});
3
CpILL

La solution la plus rapide sans plug-in si vous n'incorporez pas js à votre template est: 

Placez <script type="text/javascript"> window.CSRF_TOKEN = "{{ csrf_token }}"; </script> devant votre référence au fichier script.js dans votre modèle, puis ajoutez csrfmiddlewaretoken dans votre dictionnaire data:

$.ajax({
            type: 'POST',
            url: somepathname + "do_it/",
            data: {csrfmiddlewaretoken: window.CSRF_TOKEN},
            success: function() {
                console.log("Success!");
            }
        })

Si vous intégrez votre js au modèle, c’est aussi simple que: data: {csrfmiddlewaretoken: '{{ csrf_token }}'}

1
Marek Židek

Si, après avoir lu d'autres réponses, quelqu'un a toujours du mal à essayer, essayez ceci:

   $.ajax({
            type: "POST",
            beforeSend: function (request)
            {
                request.setRequestHeader("X-CSRF-TOKEN", "${_csrf.token}");
            },
            url: servlet_path,
            data : data,
            success : function(result) {
            console.log("Success!");
   }
});
0
Fr333du