graphql_devise 用于 Rails/Graphql/Apollo/React 中的身份验证。 “字段需要身份验证”错误

Posted

技术标签:

【中文标题】graphql_devise 用于 Rails/Graphql/Apollo/React 中的身份验证。 “字段需要身份验证”错误【英文标题】:graphql_devise for authentication in Rails/Graphql/Apollo/React. "field requires authentication" error 【发布时间】:2020-10-22 02:44:17 【问题描述】:

我有一个项目,我正在使用 Graphql 和 React/Apollo 设置 Rails API。我已将所有 google 链接设为紫色,以寻找最佳身份验证解决方案,但似乎我无法找到明确的答案。

我决定使用 graphql_devise gem,它利用了 devise 和 devise_token_auth。我本来希望找到一个 JWT 解决方案,但就是找不到。 (如果您有任何明显的建议,请告诉我!)

首先我安装了一个单独的身份验证路由,但在设置 ApolloClient 时遇到了多个端点的问题。我不知道如何将与身份验证相关的请求定向到我的身份验证端点,而让其余的请求通过我的 graphql 请求。 (如果弄清楚这是最简单的解决方案,请告诉我!)相反,我按照文档的指示将身份验证路由安装在自己的架构中:

class MyApiSchema < GraphQL::Schema

  use GraphqlDevise::SchemaPlugin.new(
    query:            Types::QueryType,
    mutation:         Types::MutationType,
    resource_loaders: [
      GraphqlDevise::ResourceLoader.new('User', only: [:login, :logout])
    ]
  )

  mutation(Types::MutationType)
  query(Types::QueryType)

并在graphql_controller.rb中编辑了执行行:

result = MyApiSchema.execute(query, variables: variables, context: graphql_context(:user), operation_name: operation_name)

至此,在 postman 中运行测试查询就成功了。我可以在没有设置任何标头的情况下使用 userLogin 突变访问 graphql 路由,并通过客户端、uid 和令牌获得成功的响应。我的其他查询的身份验证也有效 - 使用标头成功,没有标头则拒绝。

但是当我尝试在 react 中使用 useQuery 执行相同的查询时,它不起作用。在 Chrome 的 Apollo Client Developer Tools 插件中,它也不起作用,只返回 [Object object]。通过查看“网络”选项卡中的请求,我可以看到这是相同错误的结果:"photo field requires authentication"

当我窥探 Rails 服务器时,我可以看到正在接收标头。我什至可以在调用执行方法之前在我的 graphql_controller 中手动验证用户,所以我认为这不是 CORS 问题。我已经在 Rails 中设置了 rack-cors gem 以公开所需的标头。

当我深入研究代码时,graphql_devise 方法set_current_resource 似乎无法返回我的用户。这似乎源于设计方法set_user_by_token,但我一直无法弄清楚它失败的原因。

如果有人对实现此 gem 和堆栈有任何经验,我将非常感谢您的意见!如果您有更好的身份验证方法,我很想知道您的策略是什么。如果你能帮我解决这个... field requires authentication 错误,我会永远爱你。

如果我提供的信息太多/太少,或者我的问题太含糊,我们深表歉意。如果我应该知道在我的代码中询问/显示的特定内容,请告诉我。希望你能帮忙!谢谢。

【问题讨论】:

【参考方案1】:

我已经设法找到了问题所在,我想我会解释一下。

将问题追溯到 devise_token_auth gem 中的set_user_by_token 方法后,我bundle open devise_token_auth'd,并在里面放了一个byebug。这表明 @token.token 没有从标头中正确提取。

问题是我的标头 access-token 以某种方式被转换为 accessToken,因此当设计尝试使用此密钥从请求标头中设置令牌信息时,它返回了 nil

我不知道这种转换发生的原因或地点。我怀疑它来自 Apollo/React 而不是 Rails,因为我的邮递员查询的标题没有改变。在反应中,当我设置标头时,它们设置为access-token,如下所示,但似乎在我的请求生命周期的某个时刻它们被更改了。

我如何在 React 中设置标题:

const client = new ApolloClient(
  cache,
  link: new HttpLink(
    uri: 'http://localhost:3000/graphql',
    headers: 
      accessToken: localStorage.getItem('access-token'),
      client: localStorage.getItem('client'),
      uid: localStorage.getItem('uid')
    ,
  ),
);

devise_token_auth 用于从请求中选择标头的键可以在 initializers/devise_token_auth.rb 文件中更改。

我将它们编辑如下:

  config.headers_names = :'access-token' => 'accessToken',
                         :'client' => 'client',
                         :'expiry' => 'expiry',
                         :'uid' => 'uid',
                         :'token-type' => 'token-type' 

这意味着我的前端现在工作顺利,我可以通过身份验证执行查询/突变。但是,现在在我的邮递员查询中,如果我想让它们工作,我必须将标题更改为 accessToken

很高兴确切地知道我的 React 标头在什么时候更改为 camelCase,但现在,它正在工作。如果有人遇到同样的挫折,希望这会有所帮助!

【讨论】:

以上是关于graphql_devise 用于 Rails/Graphql/Apollo/React 中的身份验证。 “字段需要身份验证”错误的主要内容,如果未能解决你的问题,请参考以下文章

删除 rails 中的模型(与“rails g model Title...”相反)

Ruby on Rails - rails g 脚手架外键

Nokogiri / Rails / zlib1g-dev的问题

markdown docker-composeを使ったrails gとか

现有模型和数据库表的 rails g 脚手架

rails g 脚手架系列名称:字符串 - 这是命名约定错误还是其他原因