Je développe une application d'une page dans AngularJS en utilisant et Django Rest Framework + Django Headers CORS.
Mon problème est que le cookie "csrftoken" n'apparaît jamais dans mon navigateur lorsque j'ai contacté le backend.
Par exemple: je fais une connexion en utilisant un message. J'obtiens correctement le cookie "sessionid" mais le "csrftoken" n'apparaît jamais et je ne peux donc pas faire de publications correctes de mon client car je serai refusé en raison de l'absence du jeton csrf.
Quelques extraits de code du front/backend. Ce sont des extraits inachevés, alors ne vous attardez pas sur du code mal écrit.
class LoginView(APIView):
renderer_classes = (JSONPRenderer, JSONRenderer)
def post(self, request, format=None):
serializer = LoginSerializer(data=request.DATA)
if serializer.is_valid():
userAuth = authenticate(username=serializer.data['username'], password=serializer.data['password'])
if userAuth:
if userAuth.is_active:
login(request, userAuth)
loggedInUser = AuthUserProfile.objects.get(pk=1)
serializer = UserProfileSerializer(loggedInUser)
user = [serializer.data, {'isLogged': True}]
else:
user = {'isLogged': False}
return Response(user, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
.controller('LoginCtrl', ['$scope', '$http', 'uService', '$rootScope', function(scope, $http, User, rootScope) {
scope.login = function() {
var config = {
method: 'POST',
withCredentials: true,
url: rootScope.apiURL+'/user/login/',
data : scope.loginForm
};
$http(config)
.success(function(data, status, headers, config) {
if (status == 200) {
console.log(data[0]); //Test code
// succefull login
User.isLogged = true;
User.username = data.username;
}
else {
console.log(data); //Test code
User.isLogged = false;
User.username = '';
}
})
.error(function(data, status, headers, config) {
console.log('Testing console error');
User.isLogged = false;
User.username = '';
});
};
}]);
Quelqu'un avec de bons conseils/idées/exemples?
J'ai donc trouvé ma propre solution à cela, semble fonctionner très bien.
Voici les nouveaux extraits de mon code:
class LoginView(APIView):
renderer_classes = (JSONPRenderer, JSONRenderer)
@method_decorator(ensure_csrf_cookie)
def post(self, request, format=None):
c = {}
c.update(csrf(request))
serializer = LoginSerializer(data=request.DATA)
if serializer.is_valid():
userAuth = authenticate(username=serializer.data['username'], password=serializer.data['password'])
if userAuth:
if userAuth.is_active:
login(request, userAuth)
loggedInUser = AuthUserProfile.objects.get(pk=1)
serializer = UserProfileSerializer(loggedInUser)
user = [serializer.data, {'isLogged': True}]
else:
user = {'isLogged': False}
return Response(user, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
$http.defaults.headers.post['X-CSRFToken'] = $cookies.csrftoken;
CORS_ALLOW_HEADERS = (
'x-requested-with',
'content-type',
'accept',
'Origin',
'authorization',
'X-CSRFToken'
)
C'est ça!
Application Web AngularJS à page unique sur le sous-domaine A, parlant à une Django API JSON (REST) sur le sous-domaine B à l'aide de la protection CORS et CSRF
Comme je travaille actuellement sur une configuration similaire et que je luttais pour que CORS fonctionne correctement en combinaison avec la protection CSRF, je voulais partager mes propres apprentissages ici.
Setup - Le SPA et l'API sont tous deux sur des sous-domaines différents du même domaine:
L'application AngularJS est servie via une application Django dans le même projet que l'API Django API) de telle sorte qu'elle définit un cookie CSRF. Voir, par exemple, également Comment exécuter plusieurs sites Web à partir d'un seul Django
Django API App - Pour que la protection CORS et CSRF fonctionne, je devais faire ce qui suit sur le backend de l'API.
Dans settings.py pour cette application (une extension du projet Django settings.py):
INSTALLED_APPS = ( ... 'corsheaders', ... ) MIDDLEWARE_CLASSES = ( ... 'Django.middleware.csrf.CsrfViewMiddleware', ... 'corsheaders.middleware.CorsMiddleware', )
Voir aussi en-têtes Django CORS sur GitHub
CORS_Origin_WHITELIST = [ ... 'app.mydomain.com', ... ]
CORS_ALLOW_CREDENTIALS = True
Ajoutez le décorateur Ensure_csrf_cookie à vos vues en gérant les demandes de l'API JSON:
from Django.views.decorators.csrf import ensure_csrf_cookie @ensure_csrf_cookie def myResource(request): ...
Application Django pour AngularJS - L'application AngularJS est servie via une application Django dans le même projet. Cette application Django est configuration pour définir un cookie CSRF. Le jeton CSRF du cookie est ensuite utilisé pour les requêtes vers l'API (qui s'exécute donc dans le cadre du même Django).
Notez que presque tous les fichiers liés à l'application AngularJS ne sont que des fichiers statiques de la perspective Django. L'application Django ne doit servir que le fichier index.html pour définir le cookie.
Dans settings.py pour cette application (encore une fois une extension du Django project settings.py), définissez CSRF_COOKIE_DOMAIN de telle sorte que les sous-domaines puissent également les utiliser:
CSRF_COOKIE_DOMAIN = ".mydomain.com"
Dans views.py, je n'ai besoin que de rendre le fichier AngularJS index.html, à nouveau en utilisant le décorateur Ensure_csrf_cookie:
from Django.shortcuts import render from Django.views.decorators.csrf import ensure_csrf_cookie # Create your views here. @ensure_csrf_cookie def index(request): return render(request, 'index.html')
Envoi de demandes à l'API en utilisant AngularJS - Dans la configuration de l'application AngularJS, définissez les valeurs par défaut $ httpProvider suivantes:
$httpProvider.defaults.xsrfCookieName = 'csrftoken'; $httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken'; $httpProvider.defaults.withCredentials = true;
Encore une fois, prenez note des withCredentials, cela garantit que le cookie CSRF est utilisé dans la demande.
Ci-dessous, je montre comment vous pouvez faire des demandes à l'API en utilisant le service AngularJS $ http et JQuery:
$http.post("http://api.mydomain.com/myresource", { field1 : ..., ... fieldN : ... }, { headers : { "x-csrftoken" : $cookies.csrftoken } });
Voir aussi module ngCookies .
Utilisation de JQuery (1.11.0):
$.ajax("http://api.mydomain.com/myresource", { type: 'POST', dataType : 'json', beforeSend : function(jqXHR, settings) { jqXHR.setRequestHeader("x-csrftoken", get_the_csrf_token_from_cookie()); }, cache : false, contentType : "application/json; charset=UTF-8", data : JSON.stringify({ field1 : ..., ... fieldN : ... }), xhrFields: { withCredentials: true } });
J'espère que ça aide!!
Directement à partir des documents https://docs.djangoproject.com/en/1.9/ref/csrf/#ajax
Si votre vue ne rend pas un modèle contenant la balise de modèle csrf_token, Django peut ne pas définir le cookie de jeton CSRF. Cela est courant dans les cas où des formulaires sont ajoutés dynamiquement à la page. Pour résoudre ce cas , Django fournit un décorateur de vue qui force la configuration du cookie: assure_csrf_cookie ().
Étant donné que votre application est une application à page unique, vous pouvez ajouter ensure_csrf_cookie()
à la vue responsable du chargement initial de la page.
Une petite mise à jour de cette solution.
Depuis AngularJS 1.2.10, vous devez définir le cookie CSRF pour chaque type de demande dans le client:
$http.defaults.headers.post['X-CSRFToken'] = $cookies.csrftoken;
$http.defaults.headers.put['X-CSRFToken'] = $cookies.csrftoken;
$http.defaults.headers['delete']['X-CSRFToken'] = $cookies.csrftoken;
Cela est dû au changement suivant qui s'est produit entre 1.2.9 et 1.2.10 https://github.com/cironunes/angular.js/commit/781287473bc2e8ee67078c05b76242124dd43376
J'espère que cela aide quelqu'un!
Après So Much Search, j'ai atterri sur cette solution et son travail me forme sur le système local et également sur le serveur de faction Web en direct, c'est ma solution pour Django les utilisateurs s'il vous plaît allez dans votre dossier Apache situé dans le projet puis dans le bac que vous trouvez
<IfModule mod_headers.c>
SetEnvIf Origin (.*) AccessControlAllowOrigin=$1
Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
Header set Access-Control-Allow-Credentials true
</IfModule>
puis dans l'application js angulaire vous avez juste besoin de placer
angular.module('app', ['ngCookies'])
.config([
'$httpProvider',
'$interpolateProvider',
function($httpProvider, $interpolateProvider, $scope, $http) {
$httpProvider.defaults.withCredentials = true;
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
}]).
run([
'$http',
'$cookies',
function($http, $cookies) {
$http.defaults.headers.post['X-CSRFToken'] = $cookies.csrftoken;
}]);