55

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

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

对于 JavaScript 方面,我找到了这个redux-csrf包。我不确定如何将它与我POST使用 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 的文档,并且通常使用基于类的视图。

到目前为止,这是我的观点:

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

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

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

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

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

4

9 回答 9

56

这个问答是从 2016 年开始的,不出所料,我相信事情已经发生了变化。答案继续获得支持,因此我将添加来自其他答案的新信息,但也保留原始答案。

在评论中让我知道哪种解决方案适合您。

选项 1. 设置默认标题

在要导入 Axios 的文件中,设置默认标题:

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

选项 2. 手动将其添加到 Axios 调用中

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

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

选项 3.xsrfHeaderName通话中的设置:

添加这个:

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

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

CSRF_COOKIE_NAME = "XSRF-TOKEN"

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

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

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

axios.defaults.withCredentials = true

我试过的东西不起作用:1

于 2016-08-31T20:39:49.063 回答
23

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

在 Mac OS 上的 APPLE Safari 中不起作用

MAC Safari 的解决方案很简单,只需更改XCSRF-TOKENcsrftoken

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

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

在 settings.py 中:

    CSRF_COOKIE_NAME = "csrftoken"
于 2017-06-10T23:36:18.610 回答
15

此配置对我有用,没有问题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

于 2018-01-05T17:10:26.323 回答
5

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

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

在 settings.py 文件中:

CSRF_COOKIE_NAME = "XCSRF-TOKEN"
于 2017-03-23T19:39:09.133 回答
5

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

如果在本地进行测试,请确保您访问的是 react through127.0.0.1而不是localhost! localhost以不同的方式处理请求标头,并且不会在标头响应中显示 CSRF 令牌,这127.0.0.1将在哪里!所以不要localhost:3000尝试127.0.0.1:3000

希望这可以帮助。

于 2019-09-19T18:56:37.307 回答
1

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

来自Django 文档

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

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

于 2016-08-31T17:53:59.853 回答
1

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

添加axios.defaults.xsrfHeaderName = "X-CSRFToken";到您的应用配置,然后CSRF_COOKIE_NAME = "XSRF-TOKEN"在您的 settings.py 文件中进行设置。奇迹般有效。

于 2017-02-07T19:56:43.893 回答
1

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

我通过安装 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 虽然这可能是矫枉过正

于 2018-04-28T03:13:48.593 回答
1

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

axios.defaults.withCredentials = true
于 2019-02-17T14:13:50.803 回答