Django - 由于csrf令牌无法在Windows上运行,AJAX无法正常工作

时间:2015-07-14 11:17:17

标签: ajax django

我在Linux上开发了我的应用程序,并且AJAX请求正常工作。我已将应用程序拉到Windows机器但AJAX请求失败,我只是收到403 Forbidden错误。从在线查看,我认为这是csrf令牌的问题。在Linux中,我可以在AJAX请求的Cookie下看到csrftoken:"AjQzJy3tRZ2awslgdibkDTvQgANFQKmP"。我在Windows中看不到任何cookie。

这是我用来获取csrf cookie的Javascript代码。它来自https://docs.djangoproject.com/en/1.8/ref/csrf/

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;
}

这是我提交AJAX请求的地方:

function refreshInformation(){
$.ajax({
    type: "POST",
    url: "get_flows_info",
    data: {
           csrfmiddlewaretoken: getCookie('csrftoken')
    }
    dataType : "json",
    async : true,
    error : function(data){
        alert('AJAX error:' + data);
    },
    success : function(json_data){
            // do stuff...
    },
}); 
}

这是要求的观点:

def get_flows_info(request):
    if request.is_ajax():

          # do stuff...

        return HttpResponse(json.dumps(ret), content_type='application/json')

我发现了这个:Django CSRF check failing with an Ajax POST request 但是jQuery没有任何区别。

任何帮助?

感谢。

2 个答案:

答案 0 :(得分:4)

以下是可以做的事情:

  1. 检查CSRF令牌cookie名称。

    有关详细信息,请参阅CSRF_COOKIE_NAME

  2. ensure_csrf_cookie装饰器添加到您的视图(呈现页面的装饰器)。

    根据the docs

      

    警告

         

    如果您的视图没有呈现包含csrf_token模板标记的模板,Django可能不会设置CSRF令牌cookie。这在表单动态添加到页面的情况下很常见。为解决这种情况,Django提供了一个视图装饰器,它强制设置cookie:ensure_csrf_cookie()

  3. 假设CSRF令牌Cookie名称为csrftoken,请尝试发送X-CSRFToken标题。

    $.ajax({
        // Your options here.
        headers: {'X-CSRFToken': getCookie('csrftoken')}
    });
    
  4. 阅读Cross Site Request Forgery protection了解详情。

答案 1 :(得分:0)

我所做的只是what the Doc suggests:为所有Ajax请求添加标头,而不是在每个ajax请求中POST csrftoken。它适用于我(仅在Linux中测试)

第一部分是按照你的方式获取cookie。

<script type="text/javascript">
    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');
....

然后,正如文档建议的那样,使用此方法:

function csrfSafeMethod(method) {
        // these HTTP methods do not require CSRF protection
        return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
    }

$.ajaxSetup({
   beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    }
});

最后,像往常一样进行ajax调用,而不添加csrftoken作为额外的参数。

当您想在同一页面中执行多个ajax调用时,它非常有用。它也是推荐的。而且,如果之前您没有CSRF保护,现在您必须添加它,它不涉及更改现有代码。

在每个使用ajax的页面中重复这些行,而不是在每次ajax调用中重复令牌。