0

Je me suis cogné la tête contre le mur pendant trop longtemps en essayant de faire fonctionner l'authentification de session dans AngularJS avec la configuration de base de Django REST Framework. J'ai lu des dizaines de questions et de réponses sur les débordements de blogs, et je ne comprends tout simplement pas. J'ai une grande application sur laquelle je travaille, mais afin de faciliter une réponse à ce problème, j'ai produit une application AngularJS minimaliste au sommet d'un fork du code tutoriel de Django REST Framework here. (Toutes les dépendances frontales sont incluses dans la fourche.) Faites simplement pip install -r requires.txt, python manage.py makemigrations snippets, python manage.py migrate, puis python manage.py runserver.Application AngularJS la plus simple avec l'authentification de session à DRF

Le code d'intérêt principal est ici:

"use strict"; 
 

 
var geoint = angular.module('snippets', [ 
 
    'ngRoute', 
 
    'ngCookies', 
 
    'ngAnimate', 
 
    'ngResource', 
 
    'snippets.controllers', 
 
]) 
 

 
.config(function ($routeProvider, $httpProvider) { 
 
    $httpProvider.defaults.withCredentials = true; 
 
    $httpProvider.defaults.xsrfCookieName = 'csrftoken'; 
 
    $httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken'; 
 

 
    $routeProvider 
 
    .when('/', { 
 
     title:'Snippets - Home', 
 
     templateUrl: STATIC_URL + 'snippets/partials/snippets.html', 
 
     controller: 'SnippetsCtrl' 
 
    }) 
 
    .otherwise({ 
 
     redirectTo: '/' 
 
    }); 
 
}) 
 

 
.run(function($rootScope, $location, $http) { 
 

 
    // Get a CSRF Token 
 
    $http.get('api/auth/login/?next=/api/').then(
 
     function successCallback(response){ 
 
     console.log(response); 
 
     // Post should come back with Set-Cookie sessionid, but it doesn't! 
 
     $http.post('api/auth/login/', {username:'username', password:'password'}).then(
 
      function successCallback(response){ 
 
      console.log(response); 
 
      // Get this user's information 
 
      $http.get('api/currentuser/').then(
 
       function successCallback(response){ 
 
       console.log(response); 
 
       }) 
 
      }) 
 
     }, 
 
     function errorCallback(response){ 
 
     alert(response); 
 
     } 
 
    ); 
 

 
});
<!DOCTYPE html> 
 
<html lang="en" ng-app="pc2"> 
 
    {% load static from staticfiles %} 
 
    <head> 
 
     <meta charset="UTF-8"> 
 
     <title ng-bind="title">PC2</title> 
 
     <script>var STATIC_URL = "{% static "" %}";</script> 
 
     <link rel="stylesheet" type="text/css" href="{% static "resources/css/complete.min.css" %}"> 
 
     {% if debug %} 
 
     <script src="{% static "resources/js/_bower.js" %}"></script> 
 
     <script src="{% static "resources/js/app.js" %}"></script> 
 
     <script src="{% static "resources/js/controllers.js" %}"></script> 
 
     <script src="{% static "resources/js/directives.js" %}"></script> 
 
     <script src="{% static "resources/js/filters.js" %}"></script> 
 
     <script src="{% static "resources/js/services.js" %}"></script> 
 
     {% else %} 
 
     <script src="{% static "resources/js/complete.min.js" %}"></script> 
 
     {% endif %} 
 
    </head> 
 

 
    <body> 
 
     {% load static from staticfiles %} 
 
     <div ng-include="'{% static "resources/partials/navbar.html" %}'"></div> 
 
     <div ng-view class="container-fluid main-view"></div> 
 
    </body> 
 
</html>

Mon emboîtés et POSTs sont des instructions GET laid et évidemment pas la façon dont je voudrais vraiment le faire dans une application. Mais je pense que devrait fonctionner, et ce n'est pas le cas. J'ai utilisé le facteur et le chrome pour comprendre le problème. La racine du problème semble être que lorsque j'utilise AngularJS, le POST ne revient pas avec un Set-Cookie qui inclut sessionid. (Quand j'utilise le navigateur, c'est le cas.) Ainsi, lorsqu'il essaie d'obtenir des informations sur l'utilisateur, il n'a pas le cookie défini, et il arrive dans Django en tant qu'utilisateur anonyme. Toute aide que n'importe qui peut offrir est grandement appréciée!

Donc la question est Pourquoi cela ne fonctionne-t-il pas dans AngularJS, mais avec le navigateur? J'apprécierais également la contribution sur les meilleures pratiques, ou de meilleures façons de résoudre ce problème. (Nouveau point de terminaison DRF, utiliser $ resource, etc.)?

+0

Avez-vous essayé de définir le drapeau 'withCredentials'? Voir par exemple https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials – jonrsharpe

+0

Je ne suis pas entièrement sûr si c'est votre problème, mais je regarderais comment vous passez le nom d'utilisateur/paramètres de mot de passe dans votre requête POST. Essayez de jeter un oeil à ce fil pour référence: http://stackoverflow.com/questions/31572937/add-parameters-to-query-string-when-using-put-method-with-angulars-http –

+0

Pouvez-vous fournir un exemple de votre login avec angularjs? J'ai cloné le dépôt et cela semble fonctionner correctement. – Linovia

Répondre

0

D'accord, après avoir manipulé ce problème plus ce matin, j'ai eu la réponse. Pour la vue de connexion api par défaut de DRF, les données doivent être soumises sous forme de formulaire. Par conséquent, cela a fini par être la solution:

.run(function($rootScope, $location, $http) { 
$http.get('api/auth/login/').then(function successCallback(response){ 
console.log(response); 
$http({ 
    "method": "POST", 
    "url": 'api/auth/login/', 
    "data": $.param({username:'username', password:'password', next:'/api/currentuser'}), 
    "headers": {'Content-Type': 'application/x-www-form-urlencoded'} 
}).then(
    function successCallback(response){ 
    console.log(response); 
    })}) 

});

Je serais toujours très intéressé d'apprendre la «bonne» façon de le faire. Dois-je créer une vue de connexion DRF séparée? Devrais-je utiliser Angular $ resource au lieu de $ http calls? J'apprécierais toutes les entrées.