将它们分开时将 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的主要内容,如果未能解决你的问题,请参考以下文章
区分material-ui SelectFields并获取它们的值