【问题标题】:CSRF with Django, React+Redux using Axios使用 Django 的 CSRF,使用 Axios 的 React+Redux
【发布时间】:2017-01-08 08:04:34
【问题描述】:

这是一个教育项目,不用于生产。我不打算让用户登录作为其中的一部分。

我可以在没有用户登录的情况下使用 CSRF 令牌对 Django 进行 POST 调用吗?我可以在不使用 jQuery 的情况下做到这一点吗?我在这里超出了我的深度,并且肯定会混淆一些概念。

对于 JavaScript 方面,我发现了这个 redux-csrf 包。我不确定如何使用 Axios 将它与我的 POST 操作结合起来:

export const addJob = (title, hourly, tax) => {
  console.log("Trying to addJob: ", title, hourly, tax)
  return (dispatch) => {
    dispatch(requestData("addJob"));
    return axios({
      method: 'post',
      url: "/api/jobs",
      data: {
        "title": title,
        "hourly_rate": hourly,
        "tax_rate": tax
      },
      responseType: 'json'
    })
      .then((response) => {
        dispatch(receiveData(response.data, "addJob"));
      })
      .catch((response) => {
        dispatch(receiveError(response.data, "addJob"));
      })
  }
};

在 Django 方面,我已经阅读了 CSRF 上的 this documentation,以及一般使用基于类的视图的 this

这是我目前的看法:

class JobsHandler(View):

    def get(self, request):
        with open('./data/jobs.json', 'r') as f:
            jobs = json.loads(f.read())

        return HttpResponse(json.dumps(jobs))

    def post(self, request):
        with open('./data/jobs.json', 'r') as f:
            jobs = json.loads(f.read())

        new_job = request.to_dict()
        id = new_job['title']
        jobs[id] = new_job

        with open('./data/jobs.json', 'w') as f:
            f.write(json.dumps(jobs, indent=4, separators=(',', ': ')))

        return HttpResponse(json.dumps(jobs[id]))

我尝试使用 csrf_exempt 装饰器只是为了暂时不必担心这个问题,但这似乎不是它的工作原理。

我已将{% csrf_token %} 添加到我的模板中。

这是我的getCookie 方法(从 Django 文档中窃取):

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 = cookies[i].trim();
            // 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;
}

I've read 我需要更改 Axios CSRF 信息:

var axios = require("axios");
var axiosDefaults = require("axios/lib/defaults");

axiosDefaults.xsrfCookieName = "csrftoken"
axiosDefaults.xsrfHeaderName = "X-CSRFToken"

我在哪里粘贴实际令牌,我通过调用 getCookie('csrftoken') 获得的值?

【问题讨论】:

  • 您需要读取“csrftoken”cookie 的值并将与标头相同的值设置为“X-CSRFToken”。如果您不想使用 jquery,获取 cookie 和设置标头的实现会有所改变,但基本原理保持不变。

标签: django reactjs redux django-csrf axios


【解决方案1】:

有三种方式。您可以手动在每个爱可信通话的头令牌,你可以在每个呼叫建立爱可信的xsrfHeaderName,或者你设置默认xsrfHeaderName。 P>

1。加入它手动 H3>

让我们说你已经得到了令牌存储在一个变量叫@ 987654331值@。将头在你的爱可信电话: P>

// ...
method: 'post',
url: '/api/data',
data: {...},
headers: {"X-CSRFToken": csrfToken},
// ...

2。设置xsrfHeaderName在呼叫: H3>

添加这样的:

// ...
method: 'post',
url: '/api/data',
data: {...},
xsrfHeaderName: "X-CSRFToken",
// ...

然后在你的settings.py文件,加入这一行: P>

CSRF_COOKIE_NAME = "XSRF-TOKEN"

3。设置默认标头[1] SUP>

,而不是在每次调用定义首部,可以对Axios公司设置默认头。 P>

在您导入Axios公司拨打电话所在的文件,添加这个您的进口低于: P>

axios.defaults.xsrfHeaderName = "X-CSRFToken";

然后在你的settings.py文件,加入这一行: P>

CSRF_COOKIE_NAME = "XSRF-TOKEN"

修改 2017年6月10日 em>的):用户@yestema说,它的工作原理略有不同的Safari [2] SUP> P>

修改强>( 2019 4月17日 EM>):用户@GregHolst说,上面的Safari的溶液不起作用他。相反,他用上述溶液#3在MacOS莫哈韦Safari浏览器12.1。 (从cmets EM>) P>

修改 2019 2月17日 em>的):你可能还需要设置[3] SUP>: P>

axios.defaults.withCredentials = true

问: STRONG>这是下一节有用的人吗?我想知道,如果这个答案可能仅包括解决方案来改善。让我知道,如果你有意见请。 P>

在混乱:

Django文档 H3>

首先,从整个通道Django docs詹姆斯埃文斯referenced

...每个XMLHttpRequest的,定制的X CSRFToken头设置到 在CSRF令牌的价值。这往往是比较容易的,因为很多的JavaScript 框架提供的钩子,让头要对每一个设置 请求。

作为第一步,你必须得到CSRF令牌本身。推荐的 源,用于令牌是csrftoken cookie,它将会被设置 您启用了CSRF保护您的看法如上概括。 P>

注意

标记饼干的CSRF默认名为csrftoken,但你可以 经由CSRF_COOKIE_NAME设置控制cookie的名称。 P>

在CSRF标题名是HTTP_X_CSRFTOKEN默认,但可以 使用CSRF_HEADER_NAME设置定制它。 P>


Axios公司文档 H3>

这是从Axios docs。这表明你设置包含了cookie的名称csrftoken,和头名的位置: P>

  // `xsrfCookieName` is the name of the cookie to use as a value for xsrf token
  xsrfCookieName: 'XSRF-TOKEN', // default

  // `xsrfHeaderName` is the name of the http header that carries the xsrf token value
  xsrfHeaderName: 'X-XSRF-TOKEN', // default

条款 H3>

正如我指出的问题,您访问与document.cookie饼干。唯一使用网站我已经是CSRF令牌我把Django模板。这是一个例子:

csrftoken=5knNceCUi9nL669hGGsvCi93XfqNhwTwM9Pev7bLYBOMXGbHVrjitlkKi44CtpFU P>

有在那些容易混淆的文档被抛来抛去几个概念: P>

  • 包含CSRF令牌cookie的名称。在Django这是默认csrftoken,这是在左侧的cookie中的等号。 LI>
  • 实际的令牌。这是在右侧的一切在cookie中的等号。 LI>
  • http头携带令牌值。 LI>

东西我想,没有工作:1 P>

【讨论】:

  • 这是一个几年前,我是在做这个,当我发现的方法#2。我因为没有使用Django的。如果我的回答陈旧的信息,让我知道,我会更新它。 SPAN>
  • 选项3部作品我,但不是选项呈现下面Safari的。跨度>
  • @ ReedDunkle是它看起来细还对在MacOS莫哈韦Safari浏览器12.1。起初,我没有尝试你的选项3,因为我以为我直奔yestema的回答,但显然对我来说是走错了路。 SPAN>
  • @ ReedDunkle ..以为我已经解决了这个问题。但它已经复出了。见stackoverflow.com/questions/55842141/… 跨度>
  • 有趣的是,我发现 “X-CSRFTOKEN” Axios公司中转换为 “HTTP_X_CSRFTOKEN” 上的服务器请求头。跨度>
【解决方案2】:

我发现,axios.defaults.xsrfCookieName = "XCSRF-TOKEN";CSRF_COOKIE_NAME = "XCSRF-TOKEN"

不适用于 Mac OS 上的 APPLE Safari

MAC Safari 的解决方案很简单,只需将XCSRF-TOKEN 更改为csrftoken

所以,在js-code中应该是:

    import axios from 'axios';
    axios.defaults.xsrfHeaderName = "X-CSRFTOKEN";
    axios.defaults.xsrfCookieName = "csrftoken";

在settings.py中:

    CSRF_COOKIE_NAME = "csrftoken"

【讨论】:

  • CSRF_COOKIE_NAME 默认为'csrftoken',因此您无需编辑settings.py
  • 绝对应该是正确答案!
【解决方案3】:

这个配置对我来说没有问题Config axios CSRF django

import axios from 'axios'

/**
 * Config global for axios/django
 */
axios.defaults.xsrfHeaderName = "X-CSRFToken"
axios.defaults.xsrfCookieName = 'csrftoken'

export default axios

【讨论】:

    【解决方案4】:

    “简单的方法”几乎对我有用。这似乎有效:

    import axios from 'axios';
    axios.defaults.xsrfHeaderName = "X-CSRFTOKEN";
    axios.defaults.xsrfCookieName = "XCSRF-TOKEN";
    

    在settings.py文件中:

    CSRF_COOKIE_NAME = "XCSRF-TOKEN"
    

    【讨论】:

    • 欢迎来到 SO!请访问how to write an answer您已经提供了一个老问题的答案,该问题已经有了非常详细的答案,得到了许多人的认可和支持。您的几乎有效答案是否提供了对其他人有用但尚未详细说明的内容?
    【解决方案5】:

    在花费太多时间研究并实施上述答案后,我发现我的错误是这个问题!我已添加此答案以补充已接受的答案。我已经按照上述设置了所有内容,但对我来说 gotcha 实际上是在浏览器本身中!

    如果在本地进行测试,请确保您通过 127.0.0.1 而不是 localhost 访问 react! localhost 以不同方式处理请求标头,并且不会在标头响应中显示 CSRF 令牌,而 127.0.0.1 会!所以不要使用localhost:3000 试试127.0.0.1:3000

    希望这会有所帮助。

    【讨论】:

      【解决方案6】:

      您可以手动将 Django 提供的 CSRF 令牌添加到所有发布请求中,但这很烦人。

      来自Django docs

      虽然上述方法(手动设置 CSRF 令牌)可用于 AJAX POST 请求,但它有一些不便之处:您必须记住在每个 POST 请求中将 CSRF 令牌作为 POST 数据传递.为此,有一种替代方法:在每个 XMLHttpRequest 上,将自定义 X-CSRFToken 标头设置为 CSRF 令牌的值。这通常更容易,因为许多 JavaScript 框架提供了允许在每个请求上设置标头的钩子。

      文档中有代码可用于从 CSRF 令牌 cookie 中提取 CSRF 令牌,然后将其添加到 AJAX 请求的标头中。

      【讨论】:

        【解决方案7】:

        实际上有一个非常简单的方法可以做到这一点。

        axios.defaults.xsrfHeaderName = "X-CSRFToken"; 添加到您的应用配置中,然后在您的settings.py 文件中设置CSRF_COOKIE_NAME = "XSRF-TOKEN"。像魅力一样工作。

        【讨论】:

          【解决方案8】:

          对我来说,django 没有监听我发送的标头。我可以卷曲到 api 中,但无法使用 axios 访问它。查看cors-headers package...它可能是你最好的新朋友。

          我通过安装 django-cors-headers 修复了它

          pip install django-cors-headers
          

          然后添加

          INSTALLED_APPS = (
              ...
              'corsheaders',
              ...
          )
          

          MIDDLEWARE = [  # Or MIDDLEWARE_CLASSES on Django < 1.10
              ...
              'corsheaders.middleware.CorsMiddleware',
              'django.middleware.common.CommonMiddleware',
              ...
          ]
          

          进入我的 settings.py

          我也有

          ALLOWED_HOSTS = ['*']
          CORS_ORIGIN_ALLOW_ALL = True
          CORS_ALLOW_CREDENTIALS = True
          CORS_EXPOSE_HEADERS = (
              'Access-Control-Allow-Origin: *',
          )
          

          在我的 settings.py 中,虽然这可能有点矫枉过正

          【讨论】:

            【解决方案9】:

            除了 yestema 所说的(并得到 krescruz、cran_man、Dave Merwin 等人的回应),您还需要:

            axios.defaults.withCredentials = true
            

            【讨论】:

            • 谢谢。我将此添加到我的原始答案并链接到此。
            猜你喜欢
            • 1970-01-01
            • 2018-11-14
            • 1970-01-01
            • 1970-01-01
            • 2019-06-03
            • 1970-01-01
            • 2020-01-08
            • 2019-12-18
            • 2017-06-25
            相关资源
            最近更新 更多