如何从Django检索/提供CSRF令牌作为API

我正在开发一个使用Django REST框架作为后端的项目(比如api.somecompany.com但是有一个React.js前端( www.somecompany.com ),而Django没有提供AJAX请求。

因此,我无法使用Django的传统方法让模板包含CSRF令牌,如

{% csrf_token %}

{% csrf_token %}

我可以向Django REST Framework的api-auth\login\ url发出请求,它将返回此标头: Set-Cookie:csrftoken=tjQfRZXWW4GtnWfe5fhTYor7uWnAYqhz; expires=Mon, 01-Aug-2016 16:32:10 GMT; Max-Age=31449600; Path=/ Set-Cookie:csrftoken=tjQfRZXWW4GtnWfe5fhTYor7uWnAYqhz; expires=Mon, 01-Aug-2016 16:32:10 GMT; Max-Age=31449600; Path=/ Set-Cookie:csrftoken=tjQfRZXWW4GtnWfe5fhTYor7uWnAYqhz; expires=Mon, 01-Aug-2016 16:32:10 GMT; Max-Age=31449600; Path=/ – 但我无法检索此cookie以使用X-CSRFToken发回我的AJAX请求(我的理解是单独的子域),并且它似乎不会自动包含。

这是我的相关代码:

 // using jQuery function getCookie(name) { var cookieValue = null; if (document.cookie && document.cookie != '') { var cookies = document.cookie.split(';'); for (var i = 0; i < cookies.length; i++) { var cookie = jQuery.trim(cookies[i]); // Does this cookie string begin with the name we want? if (cookie.substring(0, name.length + 1) == (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; } function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } $.ajaxSetup({ beforeSend: function(xhr, settings) { if (!csrfSafeMethod(settings.type)) { xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')); } } }); 

当页面加载时我调用它以确保我有一个令牌:

 $.ajax(loginUrl, { method: "OPTIONS", async: false }) .done(function(data, textStatus, jqXHR) { console.log(jqXHR) app.csrftoken@ = $.cookie("csrftoken") console.log($.cookie("csrftoken")) console.log(app.csrftoken) }) .fail(function(jqXHR, textStatus, errorThrown) { console.log(jqXHR) }); 

这不是很干净,但我还没有向自己certificate这个概念。

当前端和后端位于不同的端口/域上时,对CSRF进行身份validation/保护的“正确”方法是什么?

事实上,您可以使用允许的请求来源的白名单来使用CSRF保护。

为了使这项工作,您将不得不使用Cross-Origin Resource Sharing (CORS)。 为此,我建议创建一个设置交叉共享凭据的中间件类。 有一个很好的要点概述了如何使用跨源HTTP请求标头中的一些构建。 如果需要,您可以通过这种方式通过中间件插入CSRF令牌,方法是更改​​请求的原始参考值。

django-cors-headers应用程序为您完成此操作。 如果您有兴趣,可以看看他们如何在他们的中间件文件中协商CSRF令牌。

有关详细信息,请参阅Django REST CORS文档 (他们建议使用django-cors-headers)。

如果您仍有困难,请尝试:

  1. 将AJAX请求的crossDomain参数设置为True 。 有时,如果未指定,jQuery将不会处理请求。
  2. 如果您仍未在请求中收到令牌标头,请尝试在您的view方法周围附加ensure_csrf_cookie()装饰器。 有时,当页面上没有{% csrf_token %}模板标签时(如果您没有呈现表单),Django根本不会在请求中包含令牌。