通过我的AJAX帖子,我可以使用一些帮助来遵守Django的CSRF保护机制。我遵循了这里的说明:
http://docs.djangoproject.com/en/dev/ref/contrib/csrf/
我已经复制了他们在该页面上的AJAX示例代码:
http://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax
我把一个警告打印getCookie('csrftoken')的内容之前的xhr。setRequestHeader调用,它确实被一些数据填充。我不确定如何验证令牌是正确的,但我被鼓励它正在寻找和发送一些东西。
但是Django仍然拒绝我的AJAX帖子。
这是我的JavaScript:
$.post("/memorize/", data, function (result) {
if (result != "failure") {
get_random_card();
}
else {
alert("Failed to save card data.");
}
});
下面是我从Django中看到的错误:
[23/Feb/2011 22:08:29] "POST / remember / HTTP/1.1" 403 2332
我肯定我遗漏了什么,也许很简单,但我不知道是什么。我在SO周围搜索了一下,看到了一些关于通过csrf_exempt装饰器关闭视图的CSRF检查的信息,但我发现那没什么吸引力。我已经尝试过了,它是有效的,但如果可能的话,我宁愿让我的POST以Django设计的方式工作。
为了以防有用,这里是我的视图正在做的事情的要点:
def myview(request):
profile = request.user.profile
if request.method == 'POST':
"""
Process the post...
"""
return HttpResponseRedirect('/memorize/')
else: # request.method == 'GET'
ajax = request.GET.has_key('ajax')
"""
Some irrelevent code...
"""
if ajax:
response = HttpResponse()
profile.get_stack_json(response)
return response
else:
"""
Get data to send along with the content of the page.
"""
return render_to_response('memorize/memorize.html',
""" My data """
context_instance=RequestContext(request))
谢谢你的回复!
真正的解决方案
好的,我设法找到了问题所在。它存在于Javascript代码中(正如我在下面所建议的)。
你需要的是:
$.ajaxSetup({
beforeSend: function(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;
}
if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
// Only send the token to relative URLs i.e. locally.
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
}
}
});
而不是官方文档中发布的代码:
https://docs.djangoproject.com/en/2.2/ref/csrf/
工作代码来自这个Django条目:http://www.djangoproject.com/weblog/2011/feb/08/security/
所以一般的解决方案是:“使用ajaxSetup处理程序而不是ajaxSend处理程序”。我不知道为什么会这样。但这对我来说很管用:)
以前的帖子(没有回答)
其实我也遇到了同样的问题。
它发生在更新到Django 1.2.5之后——在Django 1.2.4中AJAX POST请求没有错误(AJAX没有受到任何方式的保护,但它工作得很好)。
就像OP一样,我尝试了Django文档中发布的JavaScript代码片段。我使用的是jQuery 1.5。我还使用了“django.middleware.csrf”。CsrfViewMiddleware”中间件。
我试图遵循中间件代码,我知道它在这方面失败了:
request_csrf_token = request.META.get('HTTP_X_CSRFTOKEN', '')
然后
if request_csrf_token != csrf_token:
return self._reject(request, REASON_BAD_TOKEN)
这个“if”为真,因为“request_csrf_token”为空。
基本上这意味着头文件没有被设置。所以这JS行有什么问题吗:
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
?
我希望提供的细节将有助于我们解决这个问题:)
对于遇到这种情况并试图调试的人:
1) django CSRF检查(假设你发送了一个)在这里
2)在我的例子中,设置。CSRF_HEADER_NAME被设置为“HTTP_X_CSRFTOKEN”,我的AJAX调用正在发送一个名为“HTTP_X_CSRF_TOKEN”的头,所以东西不工作。我可以改变它在AJAX调用,或django设置。
3)如果你选择更改服务器端,找到django的安装位置,并在csrf中间件中抛出一个断点。如果你使用的是virtualenv,它应该是这样的:~/.envs/my-project/lib/python2.7/site-packages/django/middleware/csrf.py
import ipdb; ipdb.set_trace() # breakpoint!!
if request_csrf_token == "":
# Fall back to X-CSRFToken, to make things easier for AJAX,
# and possible for PUT/DELETE.
request_csrf_token = request.META.get(settings.CSRF_HEADER_NAME, '')
然后,确保csrf令牌正确地来自请求。元
4)如果你需要改变你的头,等等-改变你的设置文件中的变量