将它们分开时将 Django 的 csrf_token 放入 Vuejs

Posted

技术标签:

【中文标题】将它们分开时将 Django 的 csrf_token 放入 Vuejs【英文标题】:csrf_token of Django into Vuejs when seperate them 【发布时间】:2017-09-19 21:26:13 【问题描述】:

我正在使用 ajax 请求发送 POST,但由于 csrf_token,它得到了响应 403。我将仅使用 Vuejs 的前端和使用 Django 的后端划分为仅响应 API,因此我不能使用 Django 模板来呈现 % csrf_token % 或在会话中使用 csrftoken 来使用 getcookie('csrftoken') 就像在 Django 的文档推荐中一样。有没有人像我一样面临这个问题并得到了一些解决方案?所以谢谢你,如果你能帮助我。

【问题讨论】:

Django CSRF check failing with an Ajax POST request的可能重复 【参考方案1】:

您可以在 AJAX 请求的标头中设置 CSRF 令牌。例如,如果您使用 jquery 和 jquery.cookie 库,您可以轻松检索 Django-set csrftoken cookie,如下所示:

$.ajax(
    url : 'YOUR_URL_HERE',
    headers: 'X-CSRFToken': $.cookie('csrftoken'),
    type: 'POST',
    dataType: 'json',
    data: ,
    success: function() 

    ,
    error: function(xhr, errMsg, err) 
    ,  
);

Django 文档还包括一个关于此的部分:https://docs.djangoproject.com/en/1.11/ref/csrf/#ajax

请注意,此解决方案可能取决于您的特定 Django 设置。上面的 Django 文档链接非常清楚地详细说明了所有内容。

编辑:

鉴于即使您的初始页面请求也不是由 Django 提供的,您可以通过以下方式完成您正在寻找的内容...

1.) 在您的 Django 应用程序中创建一个手动生成并返回 CSRF 令牌的视图(使用 django.middleware.csrf.get_token):

def get_csrf_token(request):
    token = django.middleware.csrf.get_token(request)
    return JsonResponse('token': token)

2.) 您还需要在 Django URL 文件中添加一个适当的条目:

url(r'^get-token/$', get_csrf_token)

3.) 然后您的 Vue.js 应用程序可以使用此端点获取 CSRF 令牌。这不需要是用户发起的事件;例如,您可以将前端应用程序配置为在 $(document).ready() 事件中获取它。然后,使用您喜欢的 AJAX 库(在我的示例中使用 jQuery):

$.ajax(
    url: '/get-token/',
    type: 'GET',
    dataType: 'json',
    success: function(data) 
       $.cookie('csrftoken', data.token); // set the csrftoken cookie
    
);

4.) 现在您的csrftoken cookie 已设置,应该可用于后续的 POST 请求。

$.ajax(
    url : 'YOUR_URL_HERE',
    headers: 'X-CSRFToken': $.cookie('csrftoken'),
    type: 'POST',
    dataType: 'json',
    data: ,
    success: function() 

    ,
    error: function(xhr, errMsg, err) 
    ,  
);

我使用 jQuery 来实现 AJAX 功能,并使用 jQuery.cookie 库来获取和设置 cookie,当然您可以使用任何您喜欢的库来实现这些功能。

【讨论】:

不,这不是解决方案。我写道,我将 Django 和 Vuejs 分为前端和后端,所以我不能在会话中使用 csrftoken。我不使用 Django 模板进行渲染,而是使用 Vuejs。如何创建一个新的验证服务器不被阻止? 您是否至少使用 Django 提供初始页面?如果是这样,你能不在那里包含 csrf_token 吗? 嗨。我有一个问题吗?为什么我们不将cookie设置为服务器的响应,而是接收csrf_token并在javascript中设置它? 对于某些人来说,以这种方式公开令牌似乎不是一个好主意 - github.com/pillarjs/… 补充@Paolo 提出的内容,这个答案是个坏主意。它为攻击者提供了一个可以滥用的端点。 CSRF 令牌的目的是防止不良行为者代表另一个用户发出请求,因为不良行为者无法生成 CSRF 令牌来完成 POST 请求。如果使用此方案,攻击者将能够随意生成 CSRF 令牌并向服务器发出欺诈性请求。【参考方案2】:

根据Django documentation,您可以简单地在视图上使用ensure_csrf_cookie 装饰器,这将发送带有响应的令牌的cookie。

【讨论】:

这在这种情况下不起作用。由于 OP 从 Vue.js(不是 Django)获取初始页面,因此在加载该页面时不能使用 ensure_csrf_cookie @touchmybody 它与 vue 的工作方式相同,使其成为 django 中的端点并从 vuejs 请求该端点【参考方案3】:

这将非常不受欢迎,但我发现它是一种相对简单、安全且不显眼的方式来分离前端/后端。

在您的 VueJS 应用程序中,当用户尝试访问页面但未通过身份验证时,您可能会获得登录重定向。

因此,与其将其发送到 vue 路由器页面,不如将其重定向到 /account/login/ (或某些 django 应用程序路由 - 在 cloudfront 中放置异常,或 /account/login/ 的 nginx 代理以代理传递给 django) - 然后在 login.html 模板中,只需使用 javascript window.location.href 到您的 vueJS 登录页面 /login

csrf_token 将被设置为 HttpOnly 的安全 cookie(这是您想要的),并且对用户的干扰非常小,甚至不必担心。

【讨论】:

为什么如此不受欢迎?这其实是一个很好的解决方案! @Jack022 - 我知道这一点,而且我一直使用这种模式,因为 JWT 很难正确保护。但是,当我在 github 上提出这个建议时,本地测试 github.com/jazzband/django-rest-framework-simplejwt/issues/… 提出了一个问题,但我不确定它是否有效,因为测试将通过请求客户端完成,而不是 django test Client 其实前段时间我也有类似的想法,问题确实是在本地调试,我不知道如何在同一个端口上运行Vue应用程序和Django应用程序。我很确定在生产中它不会那么困难,我只需要设置 Nginx 来根据路由将请求路由到 Django 应用程序或 Vue 应用程序。请问您在开发过程中如何在本地处理它?您是否使用 webpack 在 Django 应用程序中加载 Vue? @Jack022 - 我在本地所做的一切几乎与 prod 完全相同。使用 docker-machine/docker-compose 我将 nginx 配置为 proxy_pass 路由到 Vue('web' docker 容器)或 django('backend' docker 容器)。单元测试是在其自身内部完成的,集成测试是单独运行的,这两个容器都会启动,并且测试是从第三个容器执行的,正确地测试组件,就像它们在现实世界中一样。 python.plainenglish.io/… 太棒了!非常感谢!

以上是关于将它们分开时将 Django 的 csrf_token 放入 Vuejs的主要内容,如果未能解决你的问题,请参考以下文章

Django 内置模板标签和过滤器

Django如何对dicts列表进行分页

区分material-ui SelectFields并获取它们的值

调试模式打开时的 Django 和静态文件

s-s-rS 报告 - 当固定列标题和行展开时,它们会跳到标题下

通过公共 IP 打开时控制台上的 Django 部署错误