【问题标题】:Django csrf token + AngularjsDjango csrf 令牌 + Angularjs
【发布时间】:2013-08-11 23:05:13
【问题描述】:

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

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

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

【问题讨论】:

标签: javascript python django angularjs


【解决方案1】:

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

首先,你需要在 Django 中开启 CSRF,相信你已经开启了,如果没有,请关注 Django doc https://docs.djangoproject.com/en/1.5/ref/contrib/csrf/#ajax

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

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

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

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

就是这样。

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

更新:

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

【讨论】:

  • 他仍然需要以某种方式设置cookie。
  • @dan-klasson 你说得对,Django 不提供他的 Angular 应用程序。
  • 我给了你一个 +1 来解释 csrf,因为它让我走上了正确的道路。不幸的是,这对我不起作用,我在官方文档中找不到对 xsrfCookieNAmexsrfHeaderName 的引用。不过,谢谢。
  • @Preom 仅供参考,xsrfCookieNamexsrfHeaderName 在 angular 1.2 之后记录。
  • 我在登录/ api 中获得了 Set-Cookie 标头,它是 POST。我应该何时调用 GET 请求以及如何调用?
【解决方案2】:

四处搜索后,对我有用的是来自this post,代码如下:

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 的默认选项的内容,除了 this pull request 不起作用在我写这篇文章的时候。

【讨论】:

  • 我发现以这种方式做事有问题。当我使用ctrl+shift+n 在chrome 中模拟首次站点访问时,$cookies['csrftoken'];undefined,因为在执行该行时我没有向我的django 服务器发送任何请求。我先发出OPTIONS 请求,然后全局设置$http.defaults.headers.post['X-CSRFToken'],因为$cookies.csrftoken 然后有效。
  • 我通过调用$cookiesProvider.$get()document.cookies 生成新的本地$cookies 然后更新$http 默认值上的csrf 值解决了未定义的问题。我通过可耻地创建对$cookiesProvider:var cookiesProvider_ref = null; app.config( function($cookiesProvider) {cookiesProvider_ref = $cookiesProvider }); 的全局引用来做到这一点。然后我在登录success() 回调中使用cookiesProvider_ref 再次设置$http csrf 令牌头字段。
  • 我最终不得不使用 Django 网站推荐的 getCookie 函数,因为我更喜欢这样做,而不是在 cookie 已经发送下来时包含对服务器的无意义的额外访问。 docs.djangoproject.com/en/dev/ref/csrf/#ajax
【解决方案3】:
var foo = angular.module('foo', ['bar']);

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

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

【讨论】:

  • 如下所示,这需要 AngularJS 1.1.5 或更高版本。
  • 这行得通。只是让任何阅读这篇文章的人都知道......真的很棒的帖子。
【解决方案4】:

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

请在此处查看我对AngularJS Single Page Web Application on Sub-domain A talking to a Django JSON (REST) API on Sub-domain B using CORS and CSRF protection的回答

【讨论】:

    【解决方案5】:

    如果您将 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 令牌不会随着每个请求而改变。它仅在用户登录时更改。如果您正在执行单页 Angular 应用程序,则需要确保在登录/注销时重置令牌,这应该可以正常工作。

    注意:这目前在 Django 1.10 或更高版本中不起作用,因为 CSRF 令牌在每个请求中都会发生变化。见Pass Django CSRF token to Angular with CSRF_COOKIE_HTTPONLY

    【讨论】:

      猜你喜欢
      • 2016-06-10
      • 2016-08-03
      • 2015-12-19
      • 2021-07-14
      • 2012-01-26
      • 2020-10-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多