CSRF令牌在执行POST请求时通过头部传递。

4

我正在将VueJS单页面应用程序设置在Django之上。我已经运行了Graphene端点 /api,并且在graphiql中的查询运行良好。我已经设置了前端,并且我正在使用Apollo Client查询服务器。这是我的设置:

const CSRFtoken = Cookies.get('csrftoken')

const networkInterface = createNetworkInterface({
  uri: '/api',
  transportBatching: true
})

networkInterface.use([{
  applyMiddleware (req, next) {
    if (!req.options.headers) {
      req.options.headers = {}  // Create the header object if needed.
    }
    req.options.headers['X-CSRFToken'] = CSRFtoken
    console.log('applied middleware')
    next()
  }
}])

const apolloClient = new ApolloClient({
  networkInterface,
  connectToDevTools: true
})

Vue.use(VueApollo)

const apolloProvider = new VueApollo({
  defaultClient: apolloClient
})

new Vue({
  el: '#app',
  apolloProvider,
  render: h => h(App)
});

我的POST请求带有由`Cookies`提供的`X-CSRFToken`标头值。如下截图所示:

Request Headers

不幸的是,Django拒绝访问(错误403),并显示消息:“CSRF cookie missing”。

我已经在网上搜索了很久,但没找到任何相关信息。

提前感谢您!


那么...你的问题是什么,你遇到了CSRF错误吗? - knbk
是的,403禁止访问。Django提示缺少CSRF cookie。 - Franek Madej
如果记录 const CSRFtoken,它的值是否正确? - knbk
是的,看起来很好。 - Franek Madej
1个回答

4
TL;DR: 问题是请求头中缺少cookies,包括 csrftoken
为解决该问题,请添加:
  opts: {
    credentials: 'same-origin'
  }

将以下内容添加到createNetworkInterface的初始化中。
// headers for auth
const networkInterface = createNetworkInterface({
  uri: '//localhost:8000/api',
  transportBatching: true,
  opts: {
    credentials: 'same-origin'
  }
})

长话短说:

我在过去的两天里一直在尝试解决这个问题,在Django和Apollo社区频道上询问。我非常绝望,所以考虑从Apollo转换到其他GraphQL客户端。我看了一下http://graphql.org/graphql-js/graphql-clients/ 上的参考实现。它看起来像这样:

var xhr = new XMLHttpRequest();
xhr.responseType = 'json';
xhr.open("POST", "/graphql");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader("Accept", "application/json");
xhr.onload = function () {
  console.log('data returned:', xhr.response);
}
xhr.send(JSON.stringify({query: "{ hello }"}));

我已经将它添加到我的代码中,在头部加入了CSRF token cookie,并检查了一下——它起作用了。我很高兴,但想知道为什么一个有效而另一个无效。如上所述,我发现Apollo的请求缺少Cookies Header。实际上,XMLHttpRequest的问题在于你无法发送没有添加Cookies的请求,而Fetch API允许你这样做。而Apollo则基于Fetch API。我查看了客户端文档,发现了这一点。 :)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接