GraphQL:如何防止数据库报废?

时间:2018-10-19 22:03:08

标签: graphql apollo

假设我在https://api.service.com/graphql处有一个graphql端点,该端点用于在https://www.service.com +一个iOS应用程序+一个Android应用程序上构建公司的官方UI。我想向公众公开此API,以便第三方应用程序可以通过查询数据在此API之上构建,但是我不希望它们能够抓取我的整个数据库。

假设我们有一个类型:

type Thing {
  # public fields
  field1: String
  field2: String

  # fields only available in the official UI
  field3: String
  field4: String
}

和查询:

{
  things(limit: Int!, offset: Int): [Thing]
}

仅允许公司的官方UI查询所有Thing字段并遍历所有内容的最佳方法是什么?第三方开发人员仅应针对每件事情查询field1field2,并对他们可以访问多少东西有一些限制。

选项1

我考虑过要求每个客户端在每个查询请求中都包含一个令牌,以便可以检测到官方网站,iOS应用程序和Android应用程序并将其“列入白名单”。但是,如果阻止令牌存储在客户端,是什么会阻止某人深入研究您的javascript / app捆绑并找到该令牌?

选项2

我考虑过发布具有两个不同模式/一组限制的两个不同API端点,例如:

https://api.service.com/graphql-公开记录并使用有限的架构。

https://api.service.com/graphql-anon-官方UI私下使用,并包含功能齐全/不受限制的架构。

但是,又一次阻止用户询问应用程序包并发现https://api.service.com/graphql-anon端点存在并使用它的原因呢?

1 个答案:

答案 0 :(得分:2)

首先,顺便说一句:出于多种原因,我通常会建议为您的公共API使用单独的架构和终结点:

  • 清除文档。共享模式意味着某些字段或参数将不可访问或引发错误(如果使用),这在查看GraphiQL / GraphQL Playground或自检模式。
  • 更干净的代码。您的解析器将没有那么多的分支逻辑,这将使它们更易于阅读和测试。
  • 内在差异。您可能为“内部” API实现了某些功能(例如缓存或分析),而这些功能对您的公共API毫无意义(并且可能会不必要地添加)维护端点的成本)。
  • 费率限制。。您将要为您的公共API实施某种费率限制。如果您有单独的端点,那可能会更容易做到。

那就是说,显然,维护两个单独的API会产生一定的成本,因此这并不是在所有情况下都合适的解决方案。

回到当前的问题...不管上面的考虑如何,通常,您将使用基于令牌的身份验证来限制对全部或部分API的访问,但是您不会将此令牌存储为应用程序的一部分。典型的基本流程如下:

  • 客户端使用用户的凭据调用某些登录终结点,并获取身份验证流
  • 令牌由客户端临时保留,并随每个后续请求一起发送给API
  • 用户注销后,令牌将被删除

服务器使用令牌建立用户身份,然后可以通过请求的上下文将其提供给每个GraphQL解析器功能。这使您可以仅在用户通过身份验证(或者她的角色允许访问该字段)时才有效地仅返回特定字段的数据。如果用户无法访问该字段,则根据类型,它只能返回null或空数组。

当然,您还可以为未认证的用户提供一些小的查询。这种方法使您可以根据角色而具有不同的访问级别(因此,“管理员”用户可能比“标准”用户具有更多的查询或字段,“标准”用户比未经身份验证的用户具有更多的访问权限)。

对于公共API,您可以通过类似的方式使用客户端令牌的某种组合来识别第三方客户端(也许它们不必登录,但可以使用令牌的哈希值和您所使用的秘密例如分配给他们)。如果您拥有共享模式,则可以同时支持两种身份验证机制。这样,“第三方客户端”就可以成为另一个具有某些字段子集访问权限的角色。