Django CSRF 检查因 Ajax POST 请求而失败 [英] Django CSRF check failing with an Ajax POST request

查看:27
本文介绍了Django CSRF 检查因 Ajax POST 请求而失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我可以通过我的 AJAX 帖子使用一些帮助来遵守 Django 的 CSRF 保护机制.我已按照此处的说明进行操作:

I could use some help complying with Django's CSRF protection mechanism via my AJAX post. I've followed the directions here:

http://docs.djangoproject.com/en/dev/ref/contrib/csrf/

我已经完全复制了他们在该页面上的 AJAX 示例代码:

I've copied the AJAX sample code they have on that page exactly:

http://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax

我在 xhr.setRequestHeader 调用之前放置了一个打印 getCookie('csrftoken') 内容的警报,它确实填充了一些数据.我不确定如何验证令牌是否正确,但我很高兴它正在查找和发送一些东西.

I put an alert printing the contents of getCookie('csrftoken') before the xhr.setRequestHeader call and it is indeed populated with some data. I'm not sure how to verify that the token is correct, but I'm encouraged that it's finding and sending something.

但 Django 仍然拒绝我的 AJAX 帖子.

But Django is still rejecting my AJAX post.

这是我的 JavaScript:

Here's my JavaScript:

$.post("/memorize/", data, function (result) {
    if (result != "failure") {
        get_random_card();
    }
    else {
        alert("Failed to save card data.");
    }
});

这是我从 Django 看到的错误:

Here's the error I'm seeing from Django:

[23/Feb/2011 22:08:29]POST/memorize/HTTP/1.1"403 2332

[23/Feb/2011 22:08:29] "POST /memorize/ HTTP/1.1" 403 2332

我确定我遗漏了一些东西,也许很简单,但我不知道它是什么.我已经搜索了 SO 并看到了一些有关通过 csrf_exempt 装饰器关闭我的视图的 CSRF 检查的信息,但我发现这并不吸引人.我已经试过了,它确实有效,但如果可能的话,我宁愿让我的 POST 像 Django 预期的那样工作.

I'm sure I'm missing something, and maybe it's simple, but I don't know what it is. I've searched around SO and saw some information about turning off the CSRF check for my view via the csrf_exempt decorator, but I find that unappealing. I've tried that out and it works, but I'd rather get my POST to work the way Django was designed to expect it, if possible.

以防万一它有帮助,以下是我的观点的要点:

Just in case it's helpful, here's the gist of what my view is doing:

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(正如我在下面建议的)代码中.

Ok, I managed to trace the problem down. It lies in the Javascript (as I suggested below) code.

你需要的是:

$.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/

instead of the code posted in the official docs: https://docs.djangoproject.com/en/2.2/ref/csrf/

工作代码,来自这个 Django 条目:http://www.djangoproject.com/weblog/2011/feb/08/security/

The working code, comes from this Django entry: http://www.djangoproject.com/weblog/2011/feb/08/security/

所以一般的解决方案是:使用ajaxSetup处理程序而不是ajaxSend处理程序".我不知道它为什么有效.但它对我有用:)

So the general solution is: "use ajaxSetup handler instead of ajaxSend handler". I don't know why it works. But it works for me :)

上一篇(没有回答)

我实际上遇到了同样的问题.

I'm experiencing the same problem actually.

它发生在更新到 Django 1.2.5 之后 - Django 1.2.4 中的 AJAX POST 请求没有错误(AJAX 没有以任何方式受到保护,但它工作得很好).

It occurs after updating to Django 1.2.5 - there were no errors with AJAX POST requests in Django 1.2.4 (AJAX wasn't protected in any way, but it worked just fine).

就像 OP 一样,我尝试了 Django 文档中发布的 JavaScript 代码段.我正在使用 jQuery 1.5.我也在使用django.middleware.csrf.CsrfViewMiddleware"中间件.

Just like OP, I have tried the JavaScript snippet posted in Django documentation. I'm using jQuery 1.5. I'm also using the "django.middleware.csrf.CsrfViewMiddleware" middleware.

我尝试遵循中间件代码,但我知道它失败了:

I tried to follow the the middleware code and I know that it fails on this:

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"是空的.

this "if" is true, because "request_csrf_token" is empty.

基本上这意味着未设置标头.那么这个 JS 行有什么问题吗:

Basically it means that the header is NOT set. So is there anything wrong with this JS line:

xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));

?

我希望提供的详细信息可以帮助我们解决问题:)

I hope that provided details will help us in resolving the issue :)

这篇关于Django CSRF 检查因 Ajax POST 请求而失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆