公开与私有端点的暴露
GraphQL 传统上是关于暴露单一端点的,通常位于 https://mysite.com/graphql。
Gato GraphQL 扩展了这一概念,允许我们暴露多个自定义端点,每个端点针对特定需求量身定制。例如,我们可以暴露以下端点:
/internal和/public/apps/mobile和/apps/website/clients和/visitors/development、/staging、/production/teams/development、/teams/testing、/teams/marketing/clients/A、/clients/B、clients/Z- 以上任意组合
Gato GraphQL 还支持持久化 Query,即 GraphQL query 已预先定义并存储在服务器上的端点。
本指南就如何以及何时使用各端点提供建议。
除了保护您的 Gato GraphQL API 端点安全外,我们建议您始终使用专用安全插件来加固 WordPress 站点的安全性,例如 WP Security Ninja。
端点通过 Schema Configuration 进行配置,在其中定义:
- 将 schema 设置为公开或私有
- 启用"敏感"数据元素
- 为 schema 设置命名空间
- 使用嵌套 mutation
- 定义响应头
- 通过 Access Control List 授予对 schema 元素的访问权限
- 配置 HTTP 缓存
- 以及其他许多选项
如果我们希望将某个配置应用于所有或大多数端点,可以定义一个默认 Schema Configuration。
何时使用单一端点
单一端点始终是公开的,默认暴露在 /graphql 下。
Gato GraphQL 通过"模块"进行管理,每个模块提供 GraphQL schema 的某项功能或扩展,并可根据需要启用和禁用。
为了加固 API 的安全性,最佳做法是在不需要时禁用扩展 GraphQL schema 的模块(如"Posts"、"Users"、"Comments"、"Blocks"等模块),以确保这些数据从一开始就不会被暴露。
特别是,如果 API 不打算用于数据 mutation(即创建或更新资源),最好禁用"Mutations"模块。这样做将同时禁用所有提供 mutation 的扩展(如"Post Mutations"、"Comment Mutations"等模块),这些 mutation 将永远不会在 GraphQL schema 中暴露。
单一端点在以下情况下推荐使用:
- 我们需要获取数据来支撑单个功能,且
- WordPress 网站不对公开互联网开放(即运行在开发笔记本上,或位于防火墙后方)
例如,构建 headless 站点(使用 Next.js、Gatsby 等)就属于这种情况。
何时使用公开自定义端点
自定义端点与单一端点类似,但我们可以拥有多个,每个都在其自己的 URL graphql/{custom-endpoint-slug}/ 下暴露,并且每个都可以有不同的配置。
自定义端点通过隐蔽性提供安全保障,因为只有预期目标才应该知道自定义端点的存在及其 URL。
为了进一步收紧 API 的安全性,我们可以使用 Access Control 扩展,仅在以下情况下授予端点访问权限:
- 用户已登录(或未登录)
- 用户具有某个角色
- 用户具有某项能力
- 访问者来自允许的 IP(通过 Access Control: Visitor IP 扩展)
每个自定义端点都可以有自己的 Access Control List,从而只允许其特定的目标用户访问。
当我们需要管理和自定义对 API 的访问权限时,无论是针对不同应用程序、团队、客户还是其他用途,都推荐使用自定义端点。
何时使用私有自定义端点
Gato GraphQL 通过自定义文章类型(CPT)实现自定义端点。这使我们能够将自定义端点发布为 private(也可以设为 password-protected),从而使自定义端点只能被有权访问该自定义文章的已登录用户访问,其他任何人均无法访问。
当 GraphQL 端点仅供站点管理员使用时(例如使用 GraphQL 执行管理任务),推荐使用此方法。通过完全阻止外部访客访问端点,我们将加固站点的安全性。
何时使用公开持久化 Query
持久化 Query 是端点,每个都有其自己的 URL,但 GraphQL query 已在服务器端预先定义,因此响应也是预先确定的(可以通过定义变量来实现动态化,由 URL 参数提供)。
持久化 Query 类似于 REST 端点,但我们使用 GraphQL 语言来编写 query,并且可以直接从 wp-admin 发布。发布持久化 Query 无需部署任何 PHP 代码。
由于持久化 Query 不需要在请求体中传递 GraphQL query,它们天然适合通过 GET 而非 POST 进行访问。
(单一端点和自定义端点也可以通过在端点后附加参数 ?query={ GraphQL query } 来通过 GET 访问。)
我们可以利用这一点,通过标准的 HTTP 缓存来加速 API,在客户端或客户端与服务器之间的中间层(如 CDN)缓存 GraphQL 响应。
这通过 Cache Control 扩展来实现,它根据 query 中存在的字段和指令自动计算并输出响应的 max-age 值。
建议尽可能使用持久化 Query,因为它们能大幅提升站点的安全性。
这是因为应用程序所需暴露的所有数据都已经可以通过持久化 Query 提供。这样,我们就可以不再暴露 GraphQL 单一端点(或任何自定义端点),从而消除用户访问我们(误操作或其他原因)遗留暴露的私有数据的可能性。
何时使用私有持久化 Query
与自定义端点类似,持久化 Query 也是 CPT,因此可以将其发布为 private(或 password-protected),使其只能被有权访问的已登录用户访问,其他任何人均无法访问。
每当 query 仅供内部使用时(例如为自己的用途搜索 WordPress 数据),推荐使用这些私有持久化 Query。