【发布时间】:2011-12-11 05:48:31
【问题描述】:
听起来很奇怪,但是不使用表单(可以从表面读取多个内容)使用 Javascript(例如 AJAX)发布内容的场景呢?
我应该在哪里放置 csrf_token 模板标签?我已经添加了 AJAX 修复: https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax
...但我得到“CSRF 验证失败。请求中止。” 404错误。
【问题讨论】:
听起来很奇怪,但是不使用表单(可以从表面读取多个内容)使用 Javascript(例如 AJAX)发布内容的场景呢?
我应该在哪里放置 csrf_token 模板标签?我已经添加了 AJAX 修复: https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax
...但我得到“CSRF 验证失败。请求中止。” 404错误。
【问题讨论】:
您必须在 AJAX 请求中设置自定义 HTTP 标头 X-CSRFToken。见:https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax
如果您已经遵循了该建议,那么它应该可以工作。使用 Firebug 之类的东西来监控正在发送的请求并检查标头以确保自定义标头真正被传递。如果不是,请再次检查您的实现,以确保您按照文档描述的那样进行操作。
另请注意:
由于 jQuery 1.5 中引入的错误,上面的示例在该版本上无法正常工作。确保您至少运行 jQuery 1.5.1。
【讨论】:
如果您想在没有表单的情况下发布,则配置 CSRF 令牌有两个步骤。基本上从 Cookie 中获取csrftoken,并使用 csrftoken 设置 Header(在您 POST 数据之前)。
1) 从 Cookie 中获取csrftoken。
// Function to GET csrftoken from Cookie
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');
2) 获得 csrftoken 后,应使用 csrftoken 设置 Header(在 POST 数据之前)。
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
// Function to set Request Header with `CSRFTOKEN`
function setRequestHeader(){
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
}
function postSomeData() {
.....
setRequestHeader();
$.ajax({
dataType: 'json',
type: 'POST',
url: "/url-of-some-api/",
data: data,
success: function () {
alert('success');
},
error: function () {
alert('error');
}
});
}
【讨论】:
这段代码很简单:
$.ajaxSetup({ data: {csrfmiddlewaretoken: '{{ csrf_token }}' },});
【讨论】:
一个 CSRF 令牌分配给每个会话(即每次您登录时)。因此,在您希望获取用户输入的一些数据并将其作为 ajax 调用发送到受 csrf_protect 装饰器保护的某个函数之前,请尝试在从用户获取此数据之前找到正在调用的函数。例如。必须呈现一些模板,您的用户正在其上输入数据。该模板正在由某个函数呈现。在此函数中,您可以获得 csrf 令牌,如下所示: csrf = request.COOKIES['csrftoken'] 现在将这个 csrf 值传递到上下文字典中,针对哪个模板正在呈现问题。现在在该模板中写下这一行: 现在在你的 javascript 函数中,在发出 ajax 请求之前,写下: var csrf = $('#csrf').val() 这将选择传递给模板的令牌值并将其存储在变量中csrf.现在,在进行 ajax 调用时,在您的帖子数据中,也传递此值:“csrfmiddlewaretoken”:csrf
即使您没有实现 django 表单,这也可以工作。
事实上,这里的逻辑是:你需要可以从请求中获取的令牌。所以你只需要弄清楚登录后立即调用的函数。一旦你有了这个令牌,要么进行另一个 ajax 调用来获取它,要么将它传递给你的 ajax 可以访问的某个模板。
【讨论】: