Jquery Django和Ajax:CSRF令牌尽管已传递,但仍丢失
当按下按钮时,我试图点击我使用Jquery Django和Ajax:CSRF令牌尽管已传递,但仍丢失,jquery,ajax,django,python-3.x,Jquery,Ajax,Django,Python 3.x,当按下按钮时,我试图点击我使用django rest framework创建的API端点。我正在使用jQuery的ajax方法,并传递csrf令牌,但收到一个错误,该错误声明为{“detail”:“csrf失败:csrf令牌丢失或不正确”。} 以下是我的ajax请求: $('#deactivateBtn').click(function(){ $.ajax({ url: '/api/v1/companies/{{ object.pk }}/',
django rest framework
创建的API端点。我正在使用jQuery的ajax方法,并传递csrf令牌,但收到一个错误,该错误声明为{“detail”:“csrf失败:csrf令牌丢失或不正确”。}
以下是我的ajax请求:
$('#deactivateBtn').click(function(){
$.ajax({
url: '/api/v1/companies/{{ object.pk }}/',
type: 'PATCH',
contentType: 'application/json',
data: {
'is_active': false,
'csrfmiddlewaretoken': '{{ csrf_token }}'
},
dataType: 'json',
success: function(data){
$('#deactivateBtn').hide();
console.log('hiding');
$('#deactivateSuccess').show();
}
})
});
以及我对django rest framework的身份验证设置:
REST_FRAMEWORK = {
# Use Django's standard `django.contrib.auth` permissions,
# or allow read-only access for unauthenticated users.
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
]
}
尽管在ajax请求中传递了令牌,但为什么会出现CSRF错误?我试着用django.views.decorators.csrf中的
sure\u csrf\u cookie
来装饰我的视图,但这似乎无法解决问题 Django只会在请求方法为POST
且内容类型为multipart/form data
或application/x-www-form-urlencoded
时解析请求正文。在您的示例中,两者都不是真的,因此Django不会解析主体,也找不到csrf令牌
如果不想使用具有适当内容类型的POST
请求,则需要将csrf令牌传递到X-CsrfToken
头中。这种方法适用于任何请求。Django使用以下代码:
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
这将确保令牌仅在必要时发送,并且不会意外泄漏到恶意站点 Django只会在请求方法为
POST
且内容类型为multipart/form data
或application/x-www-form-urlencoded
时解析请求正文。在您的示例中,两者都不是真的,因此Django不会解析主体,也找不到csrf令牌
如果不想使用具有适当内容类型的POST
请求,则需要将csrf令牌传递到X-CsrfToken
头中。这种方法适用于任何请求。Django使用以下代码:
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
这将确保令牌仅在必要时发送,并且不会意外泄漏到恶意站点 除了@knbk的答案之外,您还需要将
csrftoken
变量设置为
// using jQuery
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 = jQuery.trim(cookies[i]);
// 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;
}
var csrftoken = getCookie('csrftoken');
除了@knbk的答案之外,您还需要将
csrftoken
变量设置为
// using jQuery
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 = jQuery.trim(cookies[i]);
// 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;
}
var csrftoken = getCookie('csrftoken');
最后使用了发布的答案的组合——看起来我需要csrf令牌头,但实际上我可以使用模板标记获取csrf令牌:
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", '{{ csrf_token }}');
}
}
});
然后,我声明的内容类型也有一个不正确的问题,因此更改为:
// On click of deactivate button, Posting is marked as not active
$('#deactivateBtn').click(function(){
$.ajax({
url: '/api/v1/companies/{{ object.pk }}/',
type: 'PATCH',
data: {
is_active: false
},
success: function(data){
$('#deactivateBtn').hide();
console.log('hiding');
$('#deactivateSuccess').show();
}
})
});
最后,更改了django设置以包括身份验证类:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.SessionAuthentication',
),
# Use Django's standard `django.contrib.auth` permissions,
# or allow read-only access for unauthenticated users.
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
]
}
最终使用了发布的答案的组合--看起来我需要csrf令牌头,但实际上我可以使用模板标记获取csrf令牌:
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", '{{ csrf_token }}');
}
}
});
然后,我声明的内容类型也有一个不正确的问题,因此更改为:
// On click of deactivate button, Posting is marked as not active
$('#deactivateBtn').click(function(){
$.ajax({
url: '/api/v1/companies/{{ object.pk }}/',
type: 'PATCH',
data: {
is_active: false
},
success: function(data){
$('#deactivateBtn').hide();
console.log('hiding');
$('#deactivateSuccess').show();
}
})
});
最后,更改了django设置以包括身份验证类:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.SessionAuthentication',
),
# Use Django's standard `django.contrib.auth` permissions,
# or allow read-only access for unauthenticated users.
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
]
}
请显示相应的视图…请显示相应的视图…谢谢您的回答。不过,我不想使用POST方法,这毫无意义——我不是在创建新项目,而是在编辑现有项目。我将如何使用补丁方法?@orange1很抱歉,这还不清楚。如果不使用具有适当内容类型的POST请求,则需要使用
X-CsrfToken
标题。无论请求方法如何,这都会起作用。谢谢您的回答。不过,我不想使用POST方法,这毫无意义——我不是在创建新项目,而是在编辑现有项目。我将如何使用补丁方法?@orange1很抱歉,这还不清楚。如果不使用具有适当内容类型的POST请求,则需要使用X-CsrfToken
标题。无论请求方法如何,这都将起作用。