在我的JS文件中包含了Django应用程序的'django.middleware.csrf.CsrfViewMiddleware'和'django.middleware.csrf.CsrfResponseMiddleware'以及https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax中的代码。
$(document).ajaxSend(function(event, xhr, settings) {
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;
}
function sameOrigin(url) {
// url could be relative or scheme relative or absolute
var host = document.location.host; // host + port
var protocol = document.location.protocol;
var sr_origin = '//' + host;
var origin = protocol + sr_origin;
// Allow absolute or scheme relative URLs to same origin
return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
(url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
// or any other URL that isn't scheme relative or absolute i.e relative.
!(/^(\/\/|http:|https:).*/.test(url));
}
function safeMethod(method) {
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
if (!safeMethod(settings.type) && sameOrigin(settings.url)) {
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
}
});
会发生什么
生成ajax请求的html和js文件不是django生成的。 js通过jquery $ .post()与django交互。因此,获取csrf令牌的唯一方法是在发送post数据之前调用django。
在我看来,Django文档中给出的jQuery函数解决方案还没有本地cookie,并且在提交POST请求之前不等待从服务器返回cookie。但是当它与403一起获得时,它使用(现在本地存储的)cookie用于后续尝试并且工作正常。
如何解决这个问题,以便提前设置cookie并在第一次使用AJAX POST请求时使用?我错误地认为django csrf可以严格地从源自同一站点的ajax调用工作吗?
*其他与CSRF无关的问题建议使用ajax.Setup而不是ajaxSend,但根据此https://code.djangoproject.com/ticket/15284?cversion=0&cnum_hist=6,这可能会导致其他JS出现问题,因此选择了ajaxSend。*
答案 0 :(得分:0)
看起来中间件类的排序错误。要获得正确答案需要更多信息,请从settings.py。
中提供MIDDLEWARE_CLASSES将中间件'django.middleware.csrf.CsrfViewMiddleware'添加到您的 中间件类列表,MIDDLEWARE_CLASSES。 (它应该来了 在任何假定CSRF攻击的视图中间件之前 处理。)
或者,您可以特别使用装饰器csrf_protect() 您想要保护的观点(见下文)。