Django和Ajax:尽管被传递,CSRF令牌仍然丢失

时间:2017-02-28 16:58:04

标签: jquery ajax django python-3.x

我尝试按下按钮时使用{"detail":"CSRF Failed: CSRF token missing or incorrect."}命中的API端点。我使用jQuery的ajax方法,并传递了csrf令牌,但收到的错误表明 $('#deactivateBtn').click(function(){ $.ajax({ url: '/api/v1/companies/{{ object.pk }}/', type: 'PATCH', contentType: 'application/json', data: { 'is_active': false, 'csrfmiddlewaretoken': '{{ csrf_token }}' }, dataType: 'json', success: function(data){ $('#deactivateBtn').hide(); console.log('hiding'); $('#deactivateSuccess').show(); } }) });

这是我的ajax请求:

django-rest-framework

以及 REST_FRAMEWORK = { # Use Django's standard `django.contrib.auth` permissions, # or allow read-only access for unauthenticated users. 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.IsAuthenticated', ] } 的身份验证设置:

ensure_csrf_cookie

尽管在我的ajax请求中传递了令牌,为什么我会收到CSRF错误?我尝试使用来自django.views.decorators.csrf的var re = /\d+\.\d+/g; var test = "3700 NO LAND VALUE (Lease Property) (0.10)"; var floats = test.match(re); 装饰我的观点,但这似乎无法修复它。

3 个答案:

答案 0 :(得分:0)

如果请求方法为POST且内容类型为multipart/form-dataapplication/x-www-form-urlencoded,Django将仅解析请求正文。在你的例子中,两者都不是,所以Django不会解析正文而无法找到csrf标记。

如果您不想使用具有适当内容类型的POST请求,则需要将csrf标记传递到X-CsrfToken标头。该方法适用于任何请求。 Django recommends使用以下代码:

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

这将确保仅在必要时发送令牌,并且不会意外泄露到恶意站点。

答案 1 :(得分:0)

除@ knbk的答案外,您还需要设置csrftoken变量

// using jQuery
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');

并在您的django-rest-framework设置文件中:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.SessionAuthentication', // add this
    ),
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    )
}

Example App # 1

Example App # 2

Django docs

DjangoRestFramework docs - CSRF

DjangoRestFramework docs - Authentication

答案 2 :(得分:0)

使用已发布的答案的组合结束 - 看起来我需要csrf-token标头,但实际上我可以使用模板标签获取csrf-token:

    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", '{{ csrf_token }}');
            }
        }
    });

然后我声明错误的内容类型也存在问题,因此更改为:

    // On click of deactivate button, Posting is marked as not active
    $('#deactivateBtn').click(function(){
        $.ajax({
            url: '/api/v1/companies/{{ object.pk }}/',
            type: 'PATCH',

            data: {
                is_active: false
            },

            success: function(data){
                   $('#deactivateBtn').hide();
                   console.log('hiding');
                   $('#deactivateSuccess').show();
            }
        })
    });

最后,更改了django设置以包含身份验证类:

    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': (
            'rest_framework.authentication.SessionAuthentication',
        ),
        # Use Django's standard `django.contrib.auth` permissions,
        # or allow read-only access for unauthenticated users.
        'DEFAULT_PERMISSION_CLASSES': [
            'rest_framework.permissions.IsAuthenticated',
        ]
    }