Django Rest 框架、CSRF 和 Vue.js
Django Rest Framework, CSRF and Vue.js
我正在尝试使用 Vue.js 对我使用 Django Rest Framework 创建的 REST Api 执行一些 POST 方法。问题是,当我 post 时出现 CSRF Failed: CSRF token missing or incorrect.
错误。但我可以看到 csrf cookie,它被添加到 headers.
这是我的设置:
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
'rest_framework.permissions.DjangoModelPermissions'
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication'
)
}
这是我的 Vue.js 配置:
var csrftoken = Cookies.get('csrftoken');
Vue.http.headers.common['HTTP_X_CSRFTOKEN'] = csrftoken;
这是已发送的 header 的相关部分:
Cookie:djdt=hide; tabstyle=raw-tab; sessionid=1gl533mrneudxw3l9l2vg0ja1yowwmeo; csrftoken=dN85bhztB1oVRov87BsUrWTM29Ff9sjn
Host:127.0.0.1:8000
HTTP_X_CSRFTOKEN:dN85bhztB1oVRov87BsUrWTM29Ff9sjn
Origin:http://127.0.0.1:8000
Referer:http://127.0.0.1:8000/agencies/6/add-profiles/
如您所见,Cookie.csrf 和 HTTP_X_CSRFTOKEN header 匹配
我真的很难过。有什么建议吗?
所以我发布这个作为结束问题的答案。
问题是因为根据请求发送了错误的 CSRF header 名称。根据文档:
As with other HTTP headers in request.META, the header name received
from the server is normalized by converting all characters to
uppercase, replacing any hyphens with underscores, and adding an
'HTTP_' prefix to the name. For example, if your client sends a
'X-XSRF-TOKEN' header, the setting should be 'HTTP_X_XSRF_TOKEN'.
此外,我将在此处留下对 my question 的引用,它积累了几个可能导致 Django 中出现 CSRF Failed: CSRF token missing or incorrect.
错误的问题。
从 cookie 获取令牌:
function readCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
}
var csrftoken = readCookie('csrftoken');
在 headers 中发送令牌 POST:
this.$http.post('http://'+document.location.host+'/api//',{params: {foo: 'bar'}}, {headers: {"X-CSRFToken":csrftoken }}).then(function (response) {
this.response = response.data;
},
function (response) {
console.log(response);
});
我正在尝试使用 Vue.js 对我使用 Django Rest Framework 创建的 REST Api 执行一些 POST 方法。问题是,当我 post 时出现 CSRF Failed: CSRF token missing or incorrect.
错误。但我可以看到 csrf cookie,它被添加到 headers.
这是我的设置:
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
'rest_framework.permissions.DjangoModelPermissions'
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication'
)
}
这是我的 Vue.js 配置:
var csrftoken = Cookies.get('csrftoken');
Vue.http.headers.common['HTTP_X_CSRFTOKEN'] = csrftoken;
这是已发送的 header 的相关部分:
Cookie:djdt=hide; tabstyle=raw-tab; sessionid=1gl533mrneudxw3l9l2vg0ja1yowwmeo; csrftoken=dN85bhztB1oVRov87BsUrWTM29Ff9sjn
Host:127.0.0.1:8000
HTTP_X_CSRFTOKEN:dN85bhztB1oVRov87BsUrWTM29Ff9sjn
Origin:http://127.0.0.1:8000
Referer:http://127.0.0.1:8000/agencies/6/add-profiles/
如您所见,Cookie.csrf 和 HTTP_X_CSRFTOKEN header 匹配
我真的很难过。有什么建议吗?
所以我发布这个作为结束问题的答案。
问题是因为根据请求发送了错误的 CSRF header 名称。根据文档:
As with other HTTP headers in request.META, the header name received from the server is normalized by converting all characters to uppercase, replacing any hyphens with underscores, and adding an 'HTTP_' prefix to the name. For example, if your client sends a 'X-XSRF-TOKEN' header, the setting should be 'HTTP_X_XSRF_TOKEN'.
此外,我将在此处留下对 my question 的引用,它积累了几个可能导致 Django 中出现 CSRF Failed: CSRF token missing or incorrect.
错误的问题。
从 cookie 获取令牌:
function readCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
}
var csrftoken = readCookie('csrftoken');
在 headers 中发送令牌 POST:
this.$http.post('http://'+document.location.host+'/api//',{params: {foo: 'bar'}}, {headers: {"X-CSRFToken":csrftoken }}).then(function (response) {
this.response = response.data;
},
function (response) {
console.log(response);
});