Django:AJAX + CSRF POST 给出 403

Posted

技术标签:

【中文标题】Django:AJAX + CSRF POST 给出 403【英文标题】:Django: AJAX + CSRF POST gives 403 【发布时间】:2015-06-15 12:38:12 【问题描述】:

我有一个简单的代码,我在 Django 中对 URL 进行了 POST 调用,其中包含 CSRF 令牌。当我将javascript 代码粘贴到<script> 标签内的模板中时,它可以正常工作,但是一旦我将代码移动到静态文件,我就会收到HTTP 403 响应。这很奇怪!

代码如下:

$(document).ready(function() 
    $(".like-button").click(function(event) 
        $.ajax(
            url: <relative path of URL>,
            type: "POST",
            data: 
                csrfmiddlewaretoken: " csrf_token ",
                // other data items
            ,
            success: function(data, textStatus, jqXHR) ,
            error: function(jqXHR, textStatus, errorThrown) 
        );
        // other javascript code to toggle like button class
    );
);

以下是我在Django 模板中包含静态文件的方法:

% block javascript %
% load static %
<script type="text/javascript" src="% static 'app/app.js' %"></script>
% endblock %

文件位于静态目录:

app
├── static
│   └── app
│       └── app.js

和静态设置是:

STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')

注意,我的设置中还没有STATICFILE_DIRS。我可以验证文件是否正在加载和执行,因为console.log() 语句工作得很好。但是,我收到了POST 的 HTTP 403 请求。

【问题讨论】:

检查静态文件的权限。使其成为服务器可读(666 权限测试),然后重试。 @Randi:我做了chmod 666,但没有帮助。 然后确保 STATIC_ROOTSTATICFILES_DIRS 在你的 settings.py 中正确设置。如果您正在开发中,请不要忘记运行manage.py collectstatic 命令。如果您提及确切的错误消息和文件结构,也会有所帮助。 403也是csrf给出的错误,django推荐docs.djangoproject.com/en/1.7/ref/contrib/csrf通过javascript获取csrf token,我不太确定 @Randi: manage.py collectstatic 也无济于事。 【参考方案1】:

来自 Django 文档:

NOTE:
The CSRF token is also present in the DOM, but only if explicitly
included using csrf_token in a template. The cookie contains the
canonical token; the CsrfViewMiddleware will prefer the cookie to the
token in the DOM. Regardless, you’re guaranteed to have the cookie if
the token is present in the DOM, so you should use the cookie!

jQuery cookie 插件:

var csrftoken = $.cookie('csrftoken');

https://docs.djangoproject.com/en/1.7/ref/contrib/csrf/

任何不直接在模板上渲染的静态文件都不能使用 django 的模板引擎。您需要使用 csrf cookie。

在运行时检查你的 javascript,你会发现模板变量是一个空字符串。

【讨论】:

【参考方案2】:

当您直接使用标签时,django 会处理模板并将csrfmiddlewaretoken: " csrf_token " 替换为正确的标记。

现在,当您使用静态文件时,该变量不会被替换。 为了添加令牌,您应该配置 django 文档描述的 ajax 调用:https://docs.djangoproject.com/en/1.7/ref/contrib/csrf/#ajax

      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]);
            if (cookie.substring(0, name.length + 1) == (name + '=')) 
              cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
              break;
            
          
        
        return cookieValue;
      
      var csrftoken = getCookie('csrftoken');
      $.ajaxSetup(
        beforeSend: function(xhr, settings) 
          xhr.setRequestHeader("X-CSRFToken", csrftoken);
        
      );

【讨论】:

以上是关于Django:AJAX + CSRF POST 给出 403的主要内容,如果未能解决你的问题,请参考以下文章

CSRF错误Django ajax .post没有表格

Django 如何让ajax的POST方法带上CSRF令牌

Django ajax POST 扩展用于 CSRF 保护的 beforeSend 方法

如何在Django使用ajax的POST

在 Django 中使用 AJAX POST 请求进行 CSRF 检查期间禁止 403

Django CSRF 令牌错误或缺少 Ajax POST 请求