使用 Django 的 CSRF,使用 Axios 的 React+Redux [英] CSRF with Django, React+Redux using Axios

查看:29
本文介绍了使用 Django 的 CSRF,使用 Axios 的 React+Redux的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

This is an educational project, not for production. I wasn't intending to have user logins as part of this.

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

Can I make POST calls to Django with a CSRF token without having user logins? Can I do this without using jQuery? I'm out of my depth here, and surely conflating some concepts.

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

For the JavaScript side, I found this redux-csrf package. I'm not sure how to combine it with my POST action using Axios:

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 上阅读了此文档, 和 这个 一般使用基于类的视图.


On the Django side, I've read this documentation on CSRF, and this on generally working with class based views.

这是我目前的看法:

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 装饰器只是暂时不必担心这个,但这似乎不是它的工作原理.

I tried using the csrf_exempt decorator just to not have to worry about this for now, but that doesn't seem to be how that works.

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

I've added {% csrf_token %} to my template.

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

This is my getCookie method (stolen from Django docs):

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;
}

我读过我需要更改 Axios CSRF 信息:

I've read that I need to change the Axios CSRF info:

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

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

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

Where do I stick the actual token, the value I get from calling getCookie('csrftoken')?

推荐答案

共有三种方式.你可以手动在每次 axios 调用的头部包含令牌,你可以在每次调用中设置 axios 的 xsrfHeaderName,或者你设置一个默认的 xsrfHeaderName.

There are three ways. You can manually include the token in the header of each axios call, you can set axios's xsrfHeaderName in each call, or you set a default xsrfHeaderName.

假设您已将令牌的值存储在名为 csrfToken 的变量中.在 axios 调用中设置标题:

Let's say you've got the value of the token stored in a variable called csrfToken. Set the headers in your axios call:

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

2.在调用中设置xsrfHeaderName:

添加:

2. Setting xsrfHeaderName in the call:

Add this:

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

然后在您的 settings.py 文件中,添加以下行:

Then in your settings.py file, add this line:

CSRF_COOKIE_NAME = "XSRF-TOKEN"

3.设置默认标题[1]

您可以为 axios 设置默认标题,而不是在每次调用中定义标题.

3. Setting default headers[1]

Rather than defining the header in each call, you can set default headers for axios.

在导入 axios 以进行调用的文件中,在导入的下方添加:

In the file where you're importing axios to make the call, add this below your imports:

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

然后在您的 settings.py 文件中,添加以下行:

Then in your settings.py file, add this line:

CSRF_COOKIE_NAME = "XSRF-TOKEN"

编辑(2017 年 6 月 10 日):用户@yestema 表示它与 Safari 的工作方式略有不同[2]

Edit (June 10, 2017): User @yestema says that it works slightly different with Safari[2]

编辑(2019 年 4 月 17 日):用户@GregHolst 说上面的 Safari 解决方案对他不起作用.相反,他在 MacOS Mojave 上为 Safari 12.1 使用了上述解决方案 #3.(来自评论)

Edit (April 17, 2019): User @GregHolst says that the Safari solution above does not work for him. Instead, he used the above Solution #3 for Safari 12.1 on MacOS Mojave. (from comments)

编辑(2019 年 2 月 17 日):您可能还需要设置[3]:

Edit (February 17, 2019): You might also need to set[3]:

axios.defaults.withCredentials = true


问题:下一节对任何人都有用吗?我想知道是否可以通过仅包含解决方案来改进此答案.如果您有意见,请告诉我.


Question: Is this next section useful to anyone? I'm wondering if this answer might be improved by only including the solutions. Let me know if you have an opinion please.

混乱:

首先,James Evans 的 Django 文档 中的整个段落引用:

First, the whole passage from the Django docs that James Evans referenced:

...在每个 XMLHttpRequest 上,将自定义 X-CSRFToken 标头设置为CSRF 代币的价值.这通常更容易,因为许多 JavaScript框架提供了钩子,允许在每个请求.

...on each XMLHttpRequest, set a custom X-CSRFToken header to the value of the CSRF token. This is often easier, because many JavaScript frameworks provide hooks that allow headers to be set on every request.

作为第一步,您必须获取 CSRF 令牌本身.推荐的令牌的来源是 csrftoken cookie,如果如上所述,您已为您的视图启用 CSRF 保护.

As a first step, you must get the CSRF token itself. The recommended source for the token is the csrftoken cookie, which will be set if you’ve enabled CSRF protection for your views as outlined above.

注意

CSRF 令牌 cookie 默认命名为 csrftoken,但您可以通过 CSRF_COOKIE_NAME 设置控制 cookie 名称.

The CSRF token cookie is named csrftoken by default, but you can control the cookie name via the CSRF_COOKIE_NAME setting.

CSRF 头名称默认为 HTTP_X_CSRFTOKEN,但您可以使用 CSRF_HEADER_NAME 设置对其进行自定义.

The CSRF header name is HTTP_X_CSRFTOKEN by default, but you can customize it using the CSRF_HEADER_NAME setting.


Axios 文档

这是来自 Axios 文档.表示你设置了包含csrftoken的cookie的名字,以及这里的header的名字:


Axios Docs

This is from the Axios docs. It indicates that you set the name of the cookie which contains the csrftoken, and the name of the header here:

  // `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


条款

如我的问题所示,您使用 document.cookie 访问 cookie.我拥有的唯一 cookie 是我放在 Django 模板中的 CSRF 令牌.下面是一个例子:


Terms

As indicated in my question, you access cookies with document.cookie. The only cookie I have is the CSRF token I put in the Django template. Here is an example:

csrftoken=5knNceCUi9nL669hGGsvCi93XfqNhwTwM9Pev7bLYBOMXGbHVrjitlkKi44CtpFU

这些文档中有一些概念令人困惑:

There are a few concepts being thrown around in those docs that get confusing:

  • 包含 CSRF 令牌的 cookie 的名称.在 Django 中,这是默认的 csrftoken,它位于 cookie 中等号的左侧.
  • 实际令牌.这是 cookie 中等号右侧的所有内容.
  • 携带令牌值的 http 标头.
  • The name of the cookie that contains the CSRF token. In Django this is by default csrftoken, which is on the left side of the equals sign in the cookie.
  • The actual token. This is everything on the right side of the equals sign in the cookie.
  • The http header that carries the token value.

我尝试过但不起作用的事情:1

Things I tried that didn't work: 1

这篇关于使用 Django 的 CSRF,使用 Axios 的 React+Redux的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆