Подтвердить что ты не робот

Как создать запрос POST (включая токен CSRF) с использованием Django и AngularJS

Я пытаюсь создать запрос POST с помощью angular.js для этого представления 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)

Поэтому я создал этот ресурс.

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

Вызов метода get в контроллере отлично работает. URL-адрес переводится на 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!'});  
    });
}

Пока я сталкиваюсь с проблемами, выполняющими метод update/POST.

item.$update();

URL-адрес преобразуется в http://127.0.0.1:8000/pm/rest/tree/1/345, в котором отсутствует конечная косая черта. Это можно легко обойти, если вы не используете конечную косую черту в определении вашего URL.

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

вместо

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

Используя обходной путь без завершающей косой черты, я получаю код статуса 403 (Forbidden), который, вероятно, связан с тем, что я не передаю CSRF в запросе POST. Поэтому мой вопрос сводится к тому, как я могу передать токен CSRF в запрос POST, созданный angular?

Я знаю о этом подходе к передаче токена csrf через заголовки, но я ищу возможность добавить токен в тело отправить запрос, как предложено здесь. Возможно ли в angular добавить данные в тело запроса сообщения?

В качестве дополнительных показаний вы можете посмотреть эти обсуждения относительно ресурсов, удалить конечные косые черты и ресурсы ресурсов, которые в настоящее время имеют: disc1 и disc2. В одном из обсуждений один из авторов рекомендовал в настоящее время не использовать ресурсы, но вместо этого используйте этот подход.

4b9b3361

Ответ 1

Вы не можете сделать такой вызов:

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

data может быть любым, что вы хотите передать, а затем просто добавить &{{csrf_token}} к этому.

В своем ресурсе params:{} попробуйте добавить csrfmiddlewaretoken:{{csrf_token}} внутри params

Edit:

Вы можете передать данные в тело запроса как

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

а заголовки -

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

Это недокументированный issue

Ответ 2

Я знаю, что это больше 1 года, но если кто-то натыкается на ту же проблему, angular JS уже имеет механизм CIEF для получения cookie (версии AngularJS начиная с 1.1.5), и вам просто нужно сказать angular какое имя файла cookie использует django, а также HTTP-заголовок, который он должен использовать для связи с сервером.

Используйте для этого конфигурацию модуля:

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

Теперь каждый запрос будет иметь правильный токен CSRF django. По-моему, это гораздо правильнее, чем вручную помещать токен на каждый запрос, потому что он использует встроенные системы из обеих фреймворков (django и angularJS).

Ответ 3

В недавнем выпуске решения угловой версии решение не работает. Поэтому я попробовал следующее

  • Сначала добавьте тег django {% csrf_token%} в разметку.

  • Добавить инспектор $http в конфигурационном файле приложения

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

Ответ 4

var app = angular.module('angularFoo', ....

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

Ответ 5

Я использую это:

В представлении Django:

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

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

Для отправки правильного запроса вы должны преобразовать объект в param-форму:

$http.post('/items/add/', $.param({name: 'Foo'}));//Here $ is jQuery