【发布时间】:2019-10-08 00:58:53
【问题描述】:
我正在做一个项目,使用 Django 作为后端,Vue 作为前端,并尝试实现 Apollo/Graphene/GraphQL 作为数据传输层。 大部分都有效,但我不了解 CORS/CSRF 设置。
有谁知道如何通过 CSRF 令牌解决保护 graphql/graphene API 的问题?在 django 日志终端上,我得到:
Forbidden (CSRF token missing or incorrect.): /graphql/
...在 Vue/Js 控制台上我看到了
Cross-Origin Request Blocked: The Same Origin Policy disallows
reading the remote resource at http://localhost:8080/sockjs-node/
info?t=1558447812102.
你可以看到(并结帐,它是开源的)这个项目here。
http://localhost:8000、http://localhost:8000/admin 和 http://localhost:8000/ 工作得很好。查询 query{menuItems{id, title, slug, disabled}} 在 graphiql 中运行良好。
settings.py:
INSTALLED_APPS = [
# ...
'corsheaders',
'rest_framework',
'webpack_loader',
'graphene_django',
]
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware', # new
# ...
]
CORS_ORIGIN_ALLOW_ALL = DEBUG # (=True)
问题出在:
* yarn serve 在 http://localhost:8080 上运行
* ./manage.py runserver 在 http://localhost:8000 上运行,并通过 webpack 代理 Vue 前端开发服务器。
vue.config.js:
module.exports = {
// The base URL your application bundle will be deployed at
publicPath: 'http://localhost:8080',
// ...
chainWebpack: config => {
// ...
config.devServer
.public('http://localhost:8080')
// ...
vue-apollo.js:
const httpEndpoint = process.env.VUE_APP_GRAPHQL_HTTP || 'http://localhost:8000/graphql/'
编辑:如果我用csrf_exempt 包装graphql/ api urlpath,它可以工作:
urlpatterns = [ # ...
path('graphql/', csrf_exempt(GraphQLView.as_view(graphiql=True, schema=schema))),
]
但这在安全方面是 BadIdea(TM)。如何使用 Vue 与 Django 和 webpack_loader 将该令牌放入前端?
【问题讨论】:
-
小记:安装应用的顺序很重要。所以也许可以尝试解决这个问题,我相信这不会是一个解决方案,但你永远不能太确定。
-
“有谁知道如何解决这个问题?” 解决什么?你不清楚你遇到了什么实际问题。 “原因是恕我直言,由于 CORS 设置格式不正确,服务器拒绝向外部提供数据。” 您得到什么确切的错误消息来指示“格式错误的 CORS 设置”?必须做些什么来尝试解决这个问题? “但我真的放弃了。” 你放弃了试图解决问题的真正原因?现在您正在寻找解决方法?要不然是啥? “所以可能主要问题是:如何将 CSRF 令牌集成到 graphql api 请求中?” 这与 CORS 问题有什么关系?
-
解决这个问题的更好方法是从一个域/端口为所有内容提供服务,并使用前端代理将内容路由到两个服务器。我为此推荐 Traefik。
-
(补充一下我昨天的评论,如果您尝试将非标准网络用于 AJAX 或 WS 请求,您可能会陷入公司/移动防火墙的困境。如果您坚持使用 80/443可以,除非您知道您的用户群不会有问题)。
-
@nerdoc...我使用 Axios 和 vue.js 从我的后端收集所需的数据。在这种情况下,有很多关于如何允许传递 CSRF 令牌的帖子,因此 Django 支持您的调用,但或多或少您只需设置一个全局默认值以允许它:
axios.defaults.xsrfHeaderName = "X-CSRFToken"然后axios.defaults.xsrfCookieName = 'csrftoken'