65

我在使用 mod_wsgi 的 apache 服务器上运行 django,以及由 apache 直接提供的 angularjs 应用程序,而不是由 django 提供。我想对 django 服务器(运行 rest_framework)进行 POST 调用,但我遇到了 csrf 令牌问题。

有没有办法从服务器设置令牌而不{% csrf token %}作为模板的一部分(因为这些页面没有通过 django)?

  1. 我希望能够通过 GET 请求作为 cookie 获取 csrf 令牌。
  2. 然后我希望能够使用 csrf 令牌 cookie 值向 django 服务器发出 POST 请求。
4

5 回答 5

112

Django 和 AngularJS 都已经支持 CSRF,你的部分很简单。

首先,您需要在 Django 中启用 CSRF,我相信您已经这样做了,如果没有,请关注 Django 文档https://docs.djangoproject.com/en/1.5/ref/contrib/csrf/#ajax

现在,Django 将csrftoken在第一个 GET 请求上设置一个名为的 cookie,并X-CSRFToken在以后的 POST/PUT/DELETE 请求上期望一个自定义的 HTTP 标头。

对于 Angular,它需要名为的 cookieXSRF-TOKEN并将执行带有标头的 POST/PUT/DELETE 请求X-XSRF-TOKEN,因此您需要进行一些调整以使两者相互配合:

$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';

在 js 代码中的某处添加以上两行,module.config() 块是一个很好的地方。

而已。

注意:这是针对 Angular 1.1.5,旧版本可能需要不同的方法。

更新:

由于 Angular 应用程序不是由 django 提供的,为了让 cookie 被设置,Angular 应用程序需要先向 django 发出 GET 请求。

于 2013-08-09T22:45:08.943 回答
60
var foo = angular.module('foo', ['bar']);

foo.config(['$httpProvider', function($httpProvider) {
    $httpProvider.defaults.xsrfCookieName = 'csrftoken';
    $httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
}]);

并且所有使用 $http 的模块服务和控制器都将发送带有 csrf 令牌的请求。

于 2013-10-20T08:39:46.953 回答
11

在四处搜索之后,对我有用的是这篇文章,其中包含以下代码:

angular.module( '[your module name]',
    ... [some dependencies] ...
    'ngCookies',
    ... [other dependencies] ...
)
.run( function run( $http, $cookies ){

    // For CSRF token compatibility with Django
    $http.defaults.headers.post['X-CSRFToken'] = $cookies.get('csrftoken');
})

这当然是在通过 django 服务器的 GET 请求获取 cookie 之后。

我还在这里查看了其他一些答案,包括 Ye Liun 的答案,但在官方文档中找不到任何内容,其中指定了对 $httpProvider 上 xsrf 的默认选项的更改,除了这个对我不起作用的拉取请求我写这篇文章的时间。

于 2013-08-10T06:24:54.287 回答
1

我为我的 AngularJS 应用程序创建了一个 Django 应用程序,与我的 (REST) API Django 应用程序在同一个 Django 项目中,它只提供 index.html 文件(这只是一个 sym.link)。以这种方式设置 CSRF Coo​​kie 而无需额外的 GET 请求。

请在此处查看我关于子域 A 上的 AngularJS 单页 Web 应用程序使用 CORS 和 CSRF 保护与子域 B 上的 Django JSON (REST) API 交谈的答案

于 2014-03-22T22:44:48.013 回答
0

如果您将 cookie 设置为禁止 javascript 访问,则需要执行以下操作。在您的模板中,在创建 django 应用程序之前,添加以下内容:

<script>
    window.csrf_token = "{{ csrf_token }}";
</script>

在您的 Angular 应用程序中,添加以下内容:

angularApp.config(["$httpProvider", function($httpProvider) {
    $httpProvider.defaults.headers.common["X-CSRFToken"] = window.csrf_token;
}]);

至少在 Django 1.9 中,CSRF 令牌不会随着每个请求而改变。它仅在用户登录时更改。如果您正在执行单页角度应用程序,则需要确保在登录/注销时重置令牌,这应该可以正常工作。

注意:这目前在 Django 1.10 或更高版本中不起作用,因为 CSRF 令牌在每个请求中都会发生变化。请参阅使用 CSRF_COOKIE_HTTPONLY 将 Django CSRF 令牌传递给 Angular

于 2016-05-27T18:09:05.687 回答