jQuery AJAX POST在第一次调用时跳过Django CSRF令牌头

时间:2011-08-03 17:06:37

标签: jquery ajax django csrf

使用jQuery AJAX POST调用Django以获取更新的JSON集。

在我的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'));
    }
});

会发生什么

  1. 清除浏览器Cookie并加载页面。
  2. Django使用403 forbidden响应AJAX POST请求,然后使用CSRF设置cookie。但是没有JSON数据。
  3. 再次触发AJAX POST请求
  4. Django从X-CSRFToken标头接收CSRF令牌,并使用JSON集进行适当的响应。
  5. 生成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。*

1 个答案:

答案 0 :(得分:0)

看起来中间件类的排序错误。要获得正确答案需要更多信息,请从settings.py。

中提供MIDDLEWARE_CLASSES
  

将中间件'django.middleware.csrf.CsrfViewMiddleware'添加到您的   中间件类列表,MIDDLEWARE_CLASSES。 (它应该来了   在任何假定CSRF攻击的视图中间件之前   处理。

     

或者,您可以特别使用装饰器csrf_protect()   您想要保护的观点(见下文)。

来源:How to use CSRF protection