这是一个教育项目,不是为了生产。我不打算让用户登录作为其中的一部分。
我可以在没有用户登录的情况下使用 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 的文档,以及关于通常使用基于类的视图的文档。
以下是我到目前为止的观点:
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')
中获得的值?
这个问答是从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
我发现,这axios.defaults.xsrfCookieName = "XCSRF-TOKEN";
和CSRF_COOKIE_NAME = "XCSRF-TOKEN"
在 Mac OS 上的苹果 Safari 中不起作用
MAC Safari的解决方案很简单,只需将XCSRF-TOKEN
更改为csrftoken
所以,在js代码中应该是:
import axios from 'axios';
axios.defaults.xsrfHeaderName = "X-CSRFTOKEN";
axios.defaults.xsrfCookieName = "csrftoken";
在 settings.py:
CSRF_COOKIE_NAME = "csrftoken"
这个配置对我有用,没有问题 配置 axios CSRF django
import axios from 'axios'
/**
* Config global for axios/django
*/
axios.defaults.xsrfHeaderName = "X-CSRFToken"
axios.defaults.xsrfCookieName = 'csrftoken'
export default axios
在花了太多时间研究并实施上述答案后,我发现了这个问题的错误!我添加了这个答案作为接受答案的补充。我已经按照上述方式设置了所有内容,但对我来说,问题实际上在浏览器本身!
如果在本地测试,请确保您通过 127.0.0.1
而不是 localhost
访问 react ! localhost
以不同的方式处理请求标头,并且不会在标头响应中显示 CSRF 令牌,127.0.0.1
会这样做!因此,与其localhost:3000
不如尝试127.0.0.1:3000
!
希望这有帮助。
"简单的方法"几乎对我有用。这似乎有效:
import axios from 'axios';
axios.defaults.xsrfHeaderName = "X-CSRFTOKEN";
axios.defaults.xsrfCookieName = "XCSRF-TOKEN";
在 settings.py 文件中:
CSRF_COOKIE_NAME = "XCSRF-TOKEN"
你可以手动将 Django 提供的 CSRF 令牌添加到所有帖子请求中,但这很烦人。
来自 Django 文档:
虽然上述方法(手动设置 CSRF 令牌(可用于 AJAX POST 请求,但它有一些不便之处:您必须记住在每个 POST 请求中将 CSRF 令牌作为 POST 数据传入。出于这个原因,还有另一种方法:在每个XMLHttpRequest上,将自定义的X-CSRFToken标头设置为CSRF令牌的值。这通常更容易,因为许多 JavaScript 框架提供了钩子,允许在每个请求上设置标头。
这些文档包含可用于从 CSRF 令牌 cookie 中提取 CSRF 令牌的代码,然后将其添加到 AJAX 请求的标头中。
实际上有一种非常简单的方法可以做到这一点。
将axios.defaults.xsrfHeaderName = "X-CSRFToken";
添加到应用配置,然后在 settings.py 文件中设置CSRF_COOKIE_NAME = "XSRF-TOKEN"
。就像一个魅力。
对我来说,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 虽然这可能是矫枉过正
除了Yestema所说的话(krescruz,cran_man,Dave Merwin等人也附和(,您还需要:
axios.defaults.withCredentials = true