web-dev-qa-db-fra.com

Comment créer un POST demande (y compris jeton CSRF) à l'aide de Django et AngularJS

J'essaie de créer une demande POST en utilisant angular.js à cette vue Django.

class PostJSON4SlickGrid(View):
    """
    REST POST Interface for SlickGrid to update workpackages
    """

    def post(self, request, root_id, wp_id, **kwargs):
        print "in PostJSON4SlickGrid"
        print request.POST
        return HttpResponse(status=200)

J'ai donc créé cette ressource.

myModule.factory('gridData', function($resource) {
    //define resource class
    var root = {{ root.pk }};
    return $resource('{% url getJSON4SlickGrid root.pk %}:wpID/', {wpID:'@id'},{
            get: {method:'GET', params:{}, isArray:true},
            update:{method:'POST'}
    });
});

L'appel de la méthode get dans un contrôleur fonctionne bien. L'URL est traduit en http://127.0.0.1:8000/pm/rest/tree/1/.

function gridController($scope, gridData){
    gridData.get(function(result) {
        console.log(result);
        $scope.treeData = result;
        //broadcast that asynchronous xhr call finished
        $scope.$broadcast('mySignal', {fake: 'Hello!'});  
    });
}

Pendant que je suis confronté à des problèmes d’exécution de la méthode update/POST.

item.$update();

L'URL est traduite en http://127.0.0.1:8000/pm/rest/tree/1/345, sans barre oblique. Cela peut être facilement contourné lorsque vous n'utilisez pas de barre oblique finale dans votre définition d'URL.

url(r'^rest/tree/(?P<root_id>\d+)/(?P<wp_id>\d+)$', PostJSON4SlickGrid.as_view(), name='postJSON4SlickGrid'),

au lieu de

url(r'^rest/tree/(?P<root_id>\d+)/(?P<wp_id>\d+)/$', PostJSON4SlickGrid.as_view(), name='postJSON4SlickGrid'),

En utilisant la solution de contournement sans la barre oblique finale, je reçois maintenant un code de statut 403 (interdit), ce qui est probablement dû à cela. Je ne passe pas de jeton CSRF dans la requête POST. Par conséquent, ma question se résume à la façon dont je peux passer le jeton CSRF dans la demande POST créée par angular?

Je sais que cette approche permet de passer le jeton csrf via les en-têtes, mais je cherche une possibilité pour ajouter le jeton au corps de la requête post, comme suggéré ici . Est-il possible, en mode angulaire, d'ajouter des données au corps de la demande de publication?

Comme lectures supplémentaires, on peut examiner ces discussions concernant les ressources, les barres obliques de fin supprimées et les limitations actuelles des ressources: disc1 et disc2 . Dans l'une des discussions, l'un des auteurs a recommandé de n'utilisez pas de ressources, mais utilisez this à la place.

23
Thomas Kremmel

Tu ne peux pas faire un appel comme ça:

$http({
    method: 'POST',
    url: url,
    data: xsrf,
    headers: {'Content-Type': 'application/x-www-form-urlencoded'}
})

La data peut être celle que vous souhaitez transmettre, puis ajoutez simplement &{{csrf_token}} à cela.

Dans votre ressource params:{}, essayez d’ajouter csrfmiddlewaretoken:{{csrf_token}} dans la variable params.

Modifier:

Vous pouvez transmettre des données au corps de la demande en tant que

item.$update({csrfmiddlewaretoken:{{csrf_token}}})

et aux en-têtes comme

var csrf = '{{ csrf_token }}'; 
update:{method:'POST', headers: {'X-CSRFToken' : csrf }} 

C'est un sans-papiers issue

7
Pratik Mandrekar

Je sais que cela fait plus d'un an, mais si quelqu'un tombe sur le même problème, JS angular dispose déjà d'un mécanisme d'extraction de cookies CSRF (versions d'AngularJS commençant à 1.1.5) et il vous suffit de dire à Angular quel est le nom. du cookie utilisé par Django, ainsi que l’en-tête HTTP à utiliser pour communiquer avec le serveur. 

Utilisez la configuration du module pour cela:

var app = angular.module('yourApp');
app.config(['$httpProvider', function($httpProvider) {
    $httpProvider.defaults.xsrfCookieName = 'csrftoken';
    $httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
}]);

Désormais, chaque requête aura le bon jeton Django CSRF. À mon avis, cela est beaucoup plus correct que de placer manuellement le jeton sur chaque demande, car il utilise des systèmes intégrés issus des deux frameworks (Django et angularJS).

39
Anoyz

Dans la version récente d'angularjs, la solution proposée ne fonctionne pas. J'ai donc essayé ce qui suit 

  • Commencez par ajouter la balise Django {% csrf_token%} dans le balisage.

  • Ajouter un inspecteur $ http dans votre fichier de configuration d'application 

angular.module('myApp').config(function ( $httpProvider) {
   $httpProvider.interceptors.Push('myHttpRequestInterceptor'); 
});

  • Puis définissez que myHttpRequestInterceptor 

angular.module("myApp").factory('myHttpRequestInterceptor', function ( ) {

   return {
             config.headers = { 
              'X-CSRFToken': $('input[name=csrfmiddlewaretoken]').val() } 
             } 
   return config; 
  }}; 
});

il va ajouter le X-CSRFToken dans toute demande angulaire

Enfin, vous devez ajouter le middleware Django "Django.middleware.csrf.CsrfViewMiddleware '" Il résoudra le problème de CSRF.

1
mdimran

J'utilise ceci:

Dans la vue Django:

@csrf_protect
def index(request):
    #Set cstf-token cookie for rendered template
    return render_to_response('index.html', RequestContext(request))

Dans App.js:

(function(A) {
    "use strict";
    A.module('DesktopApplication', 'ngCookies' ]).config(function($interpolateProvider, $resourceProvider) {
        //I use {$ and $} as Angular directives
        $interpolateProvider.startSymbol('{$');
        $interpolateProvider.endSymbol('$}');
        //Without this Django not processed urls without trailing slash
        $resourceProvider.defaults.stripTrailingSlashes = false; 
    }).run(function($http, $cookies) {
        //Set csrf-kookie for every request
        $http.defaults.headers.post['X-CSRFToken'] = $cookies.csrftoken;
        $http.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
    });
}(this.angular));

Pour envoyer une demande correcte, vous devez convertir l'objet en param-form:

$http.post('/items/add/', $.param({name: 'Foo'}));//Here $ is jQuery
0
Dunaevsky Maxim
var app = angular.module('angularFoo', ....

app.config(["$httpProvider", function(provider) {
  provider.defaults.headers.common['X-CSRFToken'] = '<<csrftoken value from template or cookie>>';
}])
0
Serge K.