23

我正在尝试使用 angular.js 为这个 Django 视图创建一个 POST 请求。

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

虽然我在执行更新/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(禁止)状态代码,这可能是因为我没有在 POST 请求中传递CSRF令牌。因此,我的问题归结为如何将 CSRF 令牌传递到 Angular 创建的 POST 请求中?

我知道这种通过标头传递 csrf 令牌的方法,但我正在寻找将令牌添加到发布请求正文的可能性,如此处所建议。是否可以在角度将数据添加到发布请求正文?

作为其他阅读材料,您可以查看这些关于资源的讨论、删除的斜杠以及资源当前具有的限制:disc1disc2。在一次讨论中,一位作者建议目前不要使用资源,而是使用这种方法。

4

5 回答 5

39

我知道这已经超过 1 年了,但是如果有人偶然发现同样的问题,Angular JS 已经有一个 CSRF cookie 获取机制(AngularJS 的版本从 1.1.5 开始),你只需要告诉 angular 的名字是什么django 使用的 cookie,以及它应该用来与服务器通信的 HTTP 标头。

为此使用模块配置:

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

现在每个请求都将具有正确的 django CSRF 令牌。在我看来,这比在每个请求上手动放置令牌要正确得多,因为它使用了两个框架(django 和 angularJS)的内置系统。

于 2013-12-10T10:48:03.257 回答
7

你不能这样打电话吗:

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

data可以是您希望传递的任何内容,然后附加&{{csrf_token}}到该内容。

在您的资源params:{}中,尝试csrfmiddlewaretoken:{{csrf_token}}params

编辑:

您可以将数据传递给请求正文

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

并将标题作为

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

这是一个未记录的问题

于 2012-10-10T17:50:12.467 回答
1

在最近的 angularjs 版本中,提供解决方案不起作用。所以我尝试了以下

  • 首先在标记中添加 django 标签 {% csrf_token %}。

  • 在你的应用配置文件中添加一个 $http 检查器

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

  • 然后定义 myHttpRequestInterceptor

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

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

它将在所有角度请求中添加 X-CSRFToken

最后你需要添加 Django 中间件“django.middleware.csrf.CsrfViewMiddleware'”它会解决 CSRF 问题

于 2014-10-19T03:52:02.697 回答
0
var app = angular.module('angularFoo', ....

app.config(["$httpProvider", function(provider) {
  provider.defaults.headers.common['X-CSRFToken'] = '<<csrftoken value from template or cookie>>';
}])
于 2013-08-01T21:46:07.803 回答
0

我用这个:

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

要发送正确的请求,您必须将对象转换为参数形式:

$http.post('/items/add/', $.param({name: 'Foo'}));//Here $ is jQuery
于 2014-12-11T17:53:26.453 回答