403 Erreur interdite lors de la création d’une demande de publication ajax dans Django Framework

J’essaie d’intégrer jQuery dans une application Web que je réalise avec le framework Django. Cependant, j’ai de la difficulté à essayer de faire un simple appel ajax au travail. Mon fichier de modèle contenant le formulaire html et javascript permettant de gérer l’appel ajax se présente comme suit:

  $(document).ready(function() { $( "#target" ).submit(function() { console.log('Form was submitted'); $.ajax({ type: "POST", url: "/hello/", // or just url: "/my-url/path/" data: { query: $( "#query" ).val() }, success: function(data) { console.log(data); } }); return false; }); })  
{% csrf_token %}

Mon views.py qui est censé gérer l’appel ajax ressemble à views.py :

  from django.core.context_processors import csrf from django.shortcuts import render_to_response from django.template.loader import get_template from django.template import Context,RequestContext from django.views.decorators.csrf import ensure_csrf_cookie from django.http import HttpResponse # access resource def hello(request): c = {} c.update(csrf(request)) if request.is_ajax(): t = get_template('template.html') #html = t.render(Context({'result': 'hello world'})) con = RequestContext(request, {'result': 'hello world'}) return render_to_response('template.html', c, con) else: return HttpResponse('Not working!') 

J’ai essayé de suivre la documentation officielle sur la protection contre la falsification des requêtes entre sites et j’ai également examiné plusieurs questions de stackoverflow traitant d’un problème similaire. J’ai inclus le {% csrf_token %} dans mon fichier de modèle html , mais il ne semble toujours pas fonctionner. Je reçois une erreur dans la console suggérant l’échec de l’appel ajax:

 POST http://127.0.0.1:8000/hello/ 403 (FORBIDDEN) 

Comment puis-je transmettre la variable de result avec ma réponse http et obtenir le bon fonctionnement de l’appel ajax? Toute aide est très appréciée.

Édition-1

Je ne suis pas censé passer le jeton csrf avec ma demande de publication. SO conformément à la documentation, j’ai ajouté le code suivant à mon modèle javascript:

 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'); console.log(csrftoken); //Ajax call function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } $.ajaxSetup({ crossDomain: false, // obviates need for sameOrigin test beforeSend: function(xhr, settings) { if (!csrfSafeMethod(settings.type)) { xhr.setRequestHeader("X-CSRFToken", csrftoken); } } }); 

Lorsque j’actualise la page HTML du modèle dans le navigateur, la valeur null dans la console, ce qui suggère que le cookie n’est pas défini ou défini. Qu’est-ce que je rate?

Parce que vous n’avez pas posté le csrfmiddlewaretoken , Django vous interdit. ce document peut vous aider.

Pour les gars paresseux:

Premier cookie téléchargé: http://plugins.jquery.com/cookie/

Ajoutez-le à votre html:

  

Vous pouvez maintenant créer une requête POST opérationnelle:

 var csrftoken = $.cookie('csrftoken'); 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", csrftoken); } } }); $.ajax(save_url, { type : 'POST', contentType : 'application/json', data : JSON.ssortingngify(canvas), success: function () { alert("Saved!"); } }) 

Je trouve toutes les réponses précédentes sur place, mais mettons les choses en contexte.

La réponse 403 interdite provient du middleware CSRF (voir Protection contre la falsification des requêtes entre sites ):

Par défaut, une réponse “403 Forbidden” est envoyée à l’utilisateur si une demande entrante échoue aux vérifications effectuées par CsrfViewMiddleware.

De nombreuses options sont disponibles. Je recommanderais de suivre la réponse de @fivef pour que jQuery ajoute l’en X-CSRFToken tête X-CSRFToken avant chaque demande AJAX avec $.ajaxSetup .

Cette réponse nécessite le cookie jQuery plugin. Si cela n’est pas souhaitable, une autre possibilité consiste à append:

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

MAIS: si le paramètre CSRF_COOKIE_HTTPONLY est défini sur True, ce qui se produit souvent comme le recommande le middleware de sécurité , le cookie n’est pas présent, même si @ensure_csrf_cookie() est utilisé. Dans ce cas, {% csrf_token %} doit être fourni dans chaque formulaire, ce qui génère une sortie telle que . Donc, la variable csrfToken serait simplement obtenue avec:

 var csrftoken = $('input[name="csrfmiddlewaretoken"]').val(); 

Encore $.ajaxSetup fois, $.ajaxSetup serait requirejs, bien sûr.

D'autres options disponibles mais non recommandées consistent à désactiver le middleware ou la protection csrf pour le formulaire spécifique avec @csrf_exempt() .

Pour définir le cookie, utilisez le décorateur ensure_csrf_cookie à votre vue:

 from django.views.decorators.csrf import ensure_csrf_cookie @ensure_csrf_cookie def hello(request): code_here() 

Assurez-vous de ne pas mettre en cache la page / vue sur laquelle votre formulaire apparaît. Cela pourrait être la mise en cache de votre CSRF_TOKEN. Qui m’est arrivé!

Essayez d’inclure ce décorateur sur votre code d’expédition

 from django.utils.decorators import method_decorator from django.views.decorators.csrf import csrf_exempt @method_decorator(csrf_exempt, name='dispatch') def dispatch(self, request, *args, **kwargs): return super(LessonUploadWorkView,self).dispatch(request,*args,**kwargs) 

Avec SSL / https et avec CSRF_COOKIE_HTTPONLY = False, csrftoken ne figure toujours pas dans le cookie, que ce soit en utilisant la fonction getCookie (name) proposée dans django Doc ou jquery.cookie.js proposée par fivef .

Le résumé de Wtower est parfait et je pensais que cela fonctionnerait après la suppression de CSRF_COOKIE_HTTPONLY de settings.py mais cela ne se fait pas dans https!

Pourquoi csrftoken n’est pas visible dans document.cookie ???

Au lieu d’obtenir

“django_language = fr; csrftoken = rDrGI5cp98MnooPIsygWIF76vuYTkDIt”

Je reçois seulement

“django_language = fr”

POURQUOI? Comme SSL / https supprime X-CSRFToken des en-têtes, je pensais que c’était dû aux parameters d’en-tête de proxy de Nginx mais apparemment pas … Une idée?

Contrairement à Doc Notes Django , il semble impossible de travailler avec csrf_token dans les cookies avec https. La seule façon de passer csrftoken est de passer par le DOM en utilisant {% csrf_token%} en HTML et de l’obtenir dans jQuery en utilisant

 var csrftoken = $('input[name="csrfmiddlewaretoken"]').val(); 

Il est ensuite possible de le transmettre à ajax soit par header ( xhr.setRequestHeader ), soit par params .

La solution la plus rapide si vous n’intégrez pas js dans votre modèle est la suivante:

Mettez avant votre référence au fichier script.js dans votre modèle, ajoutez ensuite csrfmiddlewaretoken dans votre dictionnaire de data :

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

Si vous intégrez votre js dans le modèle, il vous data: {csrfmiddlewaretoken: '{{ csrf_token }}'}

Vous devez changer votre dossier chmod 755 et votre fichier (.php, .html) chmod 644.