Django Rest 框架、CSRF 和 Vue.js

Posted

技术标签:

【中文标题】Django Rest 框架、CSRF 和 Vue.js【英文标题】:Django Rest Framework, CSRF and Vue.js 【发布时间】:2016-06-23 05:08:53 【问题描述】:

我正在尝试使用 Vue.js 对我使用 Django Rest Framework 创建的 REST Api 执行一些 POST 方法。问题是,我在发帖时收到CSRF Failed: CSRF token missing or incorrect. 错误。但我可以看到 csrf cookie,它正在被添加到标题中。

这是我的设置:

REST_FRAMEWORK = 
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
        'rest_framework.permissions.DjangoModelPermissions'
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.BasicAuthentication'
    )

这是我的 Vue.js 配置:

var csrftoken = Cookies.get('csrftoken');
Vue.http.headers.common['HTTP_X_CSRFTOKEN'] = csrftoken;

这是发送的标头的相关部分:

Cookie:djdt=hide; tabstyle=raw-tab; sessionid=1gl533mrneudxw3l9l2vg0ja1yowwmeo; csrftoken=dN85bhztB1oVRov87BsUrWTM29Ff9sjn
Host:127.0.0.1:8000
HTTP_X_CSRFTOKEN:dN85bhztB1oVRov87BsUrWTM29Ff9sjn
Origin:http://127.0.0.1:8000
Referer:http://127.0.0.1:8000/agencies/6/add-profiles/

如您所见,Cookie.csrf 和 HTTP_X_CSRFTOKEN 标头匹配

我真的很难过。有什么建议吗?

【问题讨论】:

您使用什么CSRF_HEADER_NAME 设置?我知道 HTTP_X_CSRFTOKEN 在发送时应该是 X-CSRFTOKEN,因为 django 通常会在其内部对其进行格式化:docs.djangoproject.com/en/1.9/ref/settings/#csrf-header-name 您的应用是否在同一个域中?还是你在使用 CORS? Yerko Palma 是对的,这也可能是同源请求策略或CSRF_COOKIE_HTTPONLY 设置的问题。 小子二进制,你是对的。这是“X-CSRFTOKEN”的名字 作为一个相关问题,是否需要 vue-resources 库才能使用以下代码行设置标题:Vue.http.headers.common['X-CSRFTOKEN']? 【参考方案1】:

所以我发布这个作为结束问题的答案。

问题是因为请求发送的 CSRF 标头名称错误。根据文档:

与 request.META 中的其他 HTTP 标头一样,收到的标头名称 通过将所有字符转换为 大写,用下划线替换任何连字符,并添加一个 名称的“HTTP_”前缀。例如,如果您的客户发送一个 'X-XSRF-TOKEN' 标头,设置应为 'HTTP_X_XSRF_TOKEN'。

我还要在这里留下对my question 的引用,它积累了几个可能导致Django 中出现CSRF Failed: CSRF token missing or incorrect. 错误的问题。

【讨论】:

对于在其堆栈中使用 nginx 的任何人:如果您将设置保留为默认值,NGINX 将不会传递您的标头。您可以通过发送带有连字符而不是下划线的标头并省略 HTTP_ 部分来规避这种情况。然后,Django 会将其恢复为正确的格式。下面的代码应该适用于标准的 Django 设置var csrftoken = Cookies.get('csrftoken'); Vue.http.headers.common['X-CSRFTOKEN'] = csrftoken;【参考方案2】:

从 cookie 中获取令牌:

function readCookie(name) 
    var nameEQ = name + "=";
    var ca = document.cookie.split(';');
    for(var i=0;i < ca.length;i++) 
        var c = ca[i];
        while (c.charAt(0)==' ') c = c.substring(1,c.length);
        if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
    
    return null;


var csrftoken = readCookie('csrftoken');

在标头 POST 中发送令牌:

  this.$http.post('http://'+document.location.host+'/api//',params: foo: 'bar', headers: "X-CSRFToken":csrftoken ).then(function (response) 
            this.response = response.data;
        ,
        function (response) 
            console.log(response);
        );

【讨论】:

以上是关于Django Rest 框架、CSRF 和 Vue.js的主要内容,如果未能解决你的问题,请参考以下文章

Django/Django Rest 框架 - 禁用 CSRF

具有社交身份验证和请求发布的 Django Rest 框架(CSRF-Security)

你如何在 django rest 框架中实现 CSRF 令牌?

如何忽略发送到 Django REST 框架的 CSRF 令牌?

在 api 视图方法上禁用 CSRF(django rest 框架)

带有 CSRF/CORS 的带有 TokenAuthentication 的 Django REST 框架