Django fonctionne sur un serveur Apache utilisant mod_wsgi, ainsi que sur une application angularjs servie directement par Apache et non par Django. Je souhaite effectuer des appels POST sur le serveur Django (sous rest_framework), mais je rencontre des problèmes avec le jeton csrf.
Est-il possible de définir le jeton depuis le serveur sans ajouter {% csrf token %}
au modèle (puisque ces pages ne passent pas par Django)?
Django et AngularJS ont déjà un support CSRF, votre partie est assez simple.
Tout d’abord, vous devez activer CSRF dans Django. Je pense que vous l’avez déjà fait. Sinon, suivez Django doc https://docs.djangoproject.com/fr/1.5/ref/contrib/csrf/#ajax .
Désormais, Django définira un cookie nommé csrftoken
sur la première demande GET et attend un en-tête HTTP personnalisé X-CSRFToken
pour les demandes POST/PUT/DELETE ultérieures.
Pour Angular, il attend le cookie nommé XSRF-TOKEN
et effectuera les requêtes POST/PUT/DELETE avec l'en-tête X-XSRF-TOKEN
. Vous devez donc effectuer un petit ajustement pour que les deux se combinent:
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
Ajoutez plus de deux lignes quelque part dans votre code js, le module module.config () est un bon endroit pour cela.
C'est tout.
NOTE: Ceci est pour 1.1.5 angulaire, les versions plus anciennes pourraient nécessiter une approche différente.
Étant donné que l'application angulaire n'est pas desservie par Django, pour permettre la définition du cookie, l'application angulaire doit d'abord adresser une demande GET à Django.
var foo = angular.module('foo', ['bar']);
foo.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
}]);
Et tous les services et contrôleurs de modules, où $ http est utilisé, enverront des demandes avec le jeton csrf.
Après recherche, ce qui a fonctionné pour moi a été de ce post avec le code suivant:
angular.module( '[your module name]',
... [some dependencies] ...
'ngCookies',
... [other dependencies] ...
)
.run( function run( $http, $cookies ){
// For CSRF token compatibility with Django
$http.defaults.headers.post['X-CSRFToken'] = $cookies.get('csrftoken');
})
Ceci est bien sûr après avoir récupéré le cookie via une requête GET du serveur Django.
J'ai également examiné certaines des autres réponses ici, y compris celle de Ye Liun, mais je n'ai rien trouvé dans la documentation officielle précisant les modifications apportées aux options par défaut pour xsrf sur $ httpProvider, autre que cette demande d'extraction qui n'a pas fonctionné pour moi au moment de l'écriture de ce post.
J'ai créé une application Django pour mon application AngularJS, dans le même projet Django que mon application Django API (REST), qui sert uniquement le fichier index.html (qui n'est qu'un lien sym.link). De cette manière, le cookie CSRF est défini sans demande supplémentaire GET.
Voir ma réponse ici à propos de Application Web simple page AngularJS sur un sous-domaine A parlant à une API Django JSON (REST) sur un sous-domaine B utilisant la protection CORS et CSRF
Si vos cookies sont configurés pour interdire l'accès javascript, procédez comme suit. Dans votre modèle, avant de créer l'application Django, ajoutez ceci:
<script>
window.csrf_token = "{{ csrf_token }}";
</script>
Dans votre application angulaire, ajoutez ceci:
angularApp.config(["$httpProvider", function($httpProvider) {
$httpProvider.defaults.headers.common["X-CSRFToken"] = window.csrf_token;
}]);
Au moins par Django 1.9, le jeton CSRF ne change pas à chaque demande. Cela ne change que lorsqu'un utilisateur se connecte. Si vous utilisez une application angulaire d'une seule page, vous devez vous assurer de réinitialiser le jeton lors de la connexion/déconnexion, et cela devrait fonctionner correctement.
REMARQUE: Cela ne fonctionne pas actuellement dans Django 1.10 ou version ultérieure car le jeton CSRF change à chaque demande. Voir Passez le jeton Django CSRF à Angular avec CSRF_COOKIE_HTTPONLY