使用 Django 的 CSRF,使用 Axios 的 React+Redux [英] CSRF with Django, React+Redux using Axios
问题描述
这是一个教育项目,不用于生产.我不打算将用户登录作为其中的一部分.
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屋!