使用持久查询进行白名单
在最小化请求延迟的同时保护您的图形
该功能仅适用于GraphOS企业版计划。 您可以免费注册体验。.
免费企业试用 企业试用.
GraphQL API 开放性地用来提供灵活性和效率以方便客户端开发。然而,这种开放也引入了恶意请求的风险以及随后保护您的图所必需的安全措施。
使用 GraphOS 企业版,您可以通过维护您的GraphOS Router的持久化查询列表(PQL)来增强您的supergraph的安全性。在构建时,首先方应用注册受信任的操作到PQL。
ⓘ 注意
客户端可以向PQL注册任何类型的操作,包括查询、突变和订阅。
在运行时,路由器会将传入的请求与PQL进行对比,这可以作为PQL的操作白名单,具体取决于您的路由器配置。
您的router可以使用它的持久化查询列表(PQL)来保护您的supergraph并加快客户端操作的执行速度:
当您启用白名单时,您的router将拒绝任何未在PQL中注册的操作。
客户端应用程序可以通过提供其PQL指定的ID来执行操作,而不是提供整个操作字符串。
- 通过ID请求可以显著减少大型操作字符串的延迟和带宽使用。
- 您的router可以要求客户端通过ID提供操作,并拒绝包含在PQL中的完整操作字符串。
与自动持久化查询的不同之处
路由器还支持相关的功能,即自动持久化查询(APQ)。使用APQ,客户端可以通过发送其操作字符串的SHA256哈希值而不是完整字符串来执行GraphQL操作。
与已注册的持久化查询相比,APQ有一些限制。
自动持久化查询 | 已注册的持久化查询 | |
---|---|---|
操作性能 | ✅ 客户端可以发送标识符而不是完整的操作字符串,这可以显著减少请求大小和延迟。 | 🌟 已注册的持久化查询与APQ共享相同的性能提升机制。此外,它们还受益于查询计划缓存预热,该缓存预热从版本1.31.0的路由器默认启用。 |
编译时 vs. 运行时注册 | 操作在运行时注册。您的路由器实例必须至少从客户端接收一次给定的操作字符串,以便缓存它。 | 客户端在编译时向PQL贡献力量。您的路由器在启动时从GraphOS获取其PQL,并轮询更新,这意味着客户端始终可以使用其PQL指定的ID执行操作。 |
白名单 | ❌ APQ不提供白名单功能,因为路由器会随着时间的推移动态填充其APQ缓存,其中的操作是它接收到的任何操作。 | ✅ 客户端在GraphOS上预先注册其操作。您的路由器在启动时获取其PQL,因此可以拒绝不在PQL中存在的操作。 |
如果你只想提高请求延迟和带宽使用,APQ符合你的使用情况。如果你还希望使用操作白名单来保护你的supergraph,你应该在PQL中注册操作。
安全级别
GraphOS Router支持以下安全级别,按限制性递增的顺序:
安全级别 | 描述 |
---|---|
允许操作ID | 客户端可以选择通过提供操作的PQL指定ID来在其路由器上执行操作。 |
审计模式 | 通过提供PQL指定ID来执行操作仍然是可选的,但路由器会记录任何未注册的操作。 |
白名单 | 路由器拒绝其PQL中不存在的任何传入操作。客户端可以使用PQL指定的ID或操作字符串来执行操作。 |
仅使用ID白名单 | 客户端只能通过提供其PQL指定的ID来执行操作;路由器拒绝所有自由格式的GraphQL请求。 |
💡 提示
您可以在实现部分找到更多信息,包括配置说明。实现部分。
这些级别允许您根据每个客户的需要进行增量采用持久化查询。具体来说,路由器应使用审计模式,直到您确信所有客户受信任的操作都已注册到PQL中。有关逐步指南,请参阅增量采用部分。
实施步骤
持久化查询为不同的团队带来好处:
- 白名单有助于平台团队保护图并优化其性能。
- 应用程序开发人员可以使用已注册的操作ID编写高效的客户端代码。
实现此功能还要求各方之间进行合作。以下是在GraphOS中为安全列表实现持久查询的步骤及其通常执行的团队:
步骤 | 描述 | 责任方 |
---|---|---|
1. 创建和链接PQL | 创建并应用PQL到图变体。 | 平台团队 |
2. 路由器配置 | 更新您的路由器的YAML配置文件以在适当的安全级别 | 平台团队 |
3. 操作注册 | 从您客户端的CI/CD管道生成和发布持久查询清单(PQM)。 | 应用开发者 |
4. 客户端更新(可选) | 将客户端更新为使用操作ID而不是完整的操作字符串。 此步骤可提供性能优势,但对于安全列表不是必需的。 | 应用开发者 |
继续阅读每一步的详细信息,或跳转到逐步采用部分以获取推荐的逐步采用策略。(本部分假设您对每个实施步骤有基本的了解。)
1. 创建和链接PQL
要使用持久查询,首先需要在GraphOS Studio中的持久查询列表(PQL)。平台团队在GraphOS Studio中创建一个空的PQL,以便客户端团队可以向其中注册操作。
每个PQL都与GraphOS中的单个图相关联或“链接”。然而,一个图可以有多个PQL。例如,如果一个图需要多个PQL来分别对每个合同变体进行,则这是一个例子。您可以将PQL链接到其图的不同变体。尽管许多变体可能使用相同的PQL,但每个变体一次只能链接一个PQL。
1.1 创建PQL
- 从您在GraphOS Studio组织图的页面,通过单击其PQL按钮打开一个图的PQL页面:
💡 提示
您也可以从图的设置页面访问其PQL。
在PQL页面:
- 如果您还没有创建任何PQL,请单击创建持久查询列表。
- 如果已创建至少一个PQL,请点击右上角的新建列表。
在出现的对话框中,为您的PQL提供名称和(可选)描述,然后单击创建。
- 此时,您的空PQL已经创建。剩余的对话框步骤将帮助您进行其他设置。
第二个对话框步骤(链接)允许您将新的 PQL链接到图形中的一个存在变体。
- 您可以 跳过 此步骤,稍后链接 变体(在下一步中介绍)。
第三个对话框步骤(发布)显示您新 PQL 的唯一 ID 和发布 Rover CLI 命令的示例,以将发布操作发送到 PQL。
- 目前,您可以保留 PQL 为空。客户团队可以在稍后的步骤中将操作发布到其中。
- 保存此 Rover CLI 命令,以便在客户团队发布操作时传递。
第四个和最后一个对话框步骤(配置)显示您应用到路由器的配置选项,以开始使用您的 PQL。我们将在稍后的步骤中介绍这些。
点击 完成 关闭对话框并保存您刚刚创建的 PQL。
1.2 将 PQL 链接到变体
创建 PQL 后,您可以将其链接到图形的一个或多个 变体。与链接的变体相关联的每个 router 实例都会自动从 GraphOS 获取其 PQL。
💡 提示
将空或不完整的 PQL 链接到变体是安全的,因为您的 router 不会使用其 PQL 进行任何操作,直到您将其配置为这样做(将在稍后的步骤中介绍)。
在您的图形的 PQL 页面的表格中,打开 ••• 菜单下的 操作 列中要链接的 PQL 的 。点击 链接和断开链接变体。
在出现的对话框中,使用下拉菜单选择您想将 PQL 链接到其上的任何 变体。
💡 提示
作为最佳实践,您可以首先将您的 PQLs 链接到一个 staging 环境,然后再链接到生产环境。
- 点击 保存。
在将 PQL 链接到变体后,GraphOS 会将 PQL 使其在 Uplink 中可用,Uplink 是将配置发送到运行时路由器的服务。一旦 配置完成,路由器将轮询 Uplink 确保使用 最新版本的 linked 变体的 PQL。
2. 路由器配置
GraphOS 路由器是强制执行白名单的关键组件。
一旦图变体具有关联的 PQL,您可以通过以下步骤配置路由器实例以获取和使用 PQL:
确保您的 router 实例已准备好与 PQLs 一起工作:
- 确保您正在使用版本 v1.32.0 或更高版本的 router。 (该功能在版本 v1.25.0 中发布为预览版,并在 v1.32.0 中正式推出。)预览,在版本 v1.25.0 中发布并在 v1.32.0 中正式推出。)
- 请确保您的 router 实例连接到了您的 GraphOSEnterprise 组织,并且与您的 PQL 相关联的 variant 相关联。
在您的 router's YAML 配置文件中设置所需的安全级别。有关支持选项,请参阅 router 安全级别。首次实施持久查询时,最好从 审计模式或“Dry Run”(试运行)模式开始。
将您的更新后的 router 实例部署以开始使用您的 PQL。
一旦您的组织的 PQL 注册了所有客户的 operations 并且您确保您的客户端应用程序只发送已注册的 operations,您可以更新您的 router 配置到 白名单安全级别。
Router 安全级别
GraphOS Router支持以下安全级别,按限制性递增的顺序:
- 允许操作 ID: 客户可以选择通过提供操作 PQL 指定的 ID 来执行操作。
- 所有其他级别也提供此核心功能。
- 此级别不提供白名单。
- 审计模式: 通过提供 PQL 指定的 ID 来执行操作仍然可选,但 router 也记录任何未注册的操作。
- 此级别充当试运行,并帮助您在启用白名单之前识别可能需要注册的操作。
- 白名单: router 拒绝任何未在其 PQL 中出现的操作。请求可以使用 ID 或操作字符串。
- 在转向此安全级别之前,请确保所有客户端 operations 已存在于您的 PQL 中。
- 只使用 ID 的白名单: router 拒绝任何非结构化 GraphQL 操作。客户端只能通过提供他们的 PQL 指定的 ID 来执行操作。
- 在转向此安全级别之前,请确保所有客户端通过提供他们的 PQL 指定的 ID 来执行操作。
在采用持久查询时,您应该从一个较少限制的安全级别开始,如 审计模式。然后,在您的团队更新所有客户端之后,可以启用更限制性的级别。
以下为每个级别的示例 YAML 配置。有关选项的详细信息,请参考 router 配置选项。
ⓘ 注意
从版本1.25.0
到 1.32.0
,persisted_queries
配置选项的名称已更改为 preview_persisted_queries
。将您的 router 升级至版本 1.32.0
或更高版本,以使用此功能的一般可用版本以及下面的示例配置片段。
允许操作ID
要仅为了减少网络带宽和延迟(而非为了安全列表)使用持久化查询,请添加以下最小配置:
persisted_queries:enabled: true
ⓘ 注意
您可以使用此安全级别与或不与 自动持久化查询 启用。
此模式允许客户端通过提供其 PQL-指定的 ID 来执行操作,而不是提供完整的操作字符串。您的 router 也继续接受完整的操作字符串,即使对于其 PQL 中不出现的操作。
审计模式(模拟运行)
开启日志记录对于衡量您的客户端应用程序的安全性至关重要。日志记录可以识别您需要将其添加到您的 PQL 或阻止您的客户端应用程序执行的 operations。
要为未注册的查询启用日志记录,启用 log_unknown
属性:
persisted_queries:enabled: truelog_unknown: true
ⓘ 注意
您可以使用审计模式与或不与 自动持久化查询 启用。
未注册的 operations 出现在您的 router 的日志中。
例如
2023-08-02T11:51:59.833534Z WARN [trace_id=5006cef73e985810eb086e5900945807] unknown operation operation_body="query ExampleQuery {\n me {\n id\n }\n}\n"
如果您的 router 接收到在 PQL 中注册的操作,则不会输出日志消息。
您可以使用这些 router 日志来审计发送到您的 router 的操作,并要求客户端团队 添加新操作 到您的 PQL 中(如果需要)。
白名单
⚠️ 注意
在应用此配置之前,请确保您的 PQL 包含所有 GraphQL 操作,这是所有激活版本的客户端都会执行的操作。如果您在未确保这一点的情摊下启用安全列表,则您的 router 将会拒绝任何未发布客户端操作。
使用以下配置,您的 router 只允许存在于其 PQL 中的 GraphQL 操作,而拒绝所有其他操作:
persisted_queries:enabled: truelog_unknown: truesafelist:enabled: truerequire_id: falseapq:enabled: false # APQ must be turned off
ⓘ 注意
要启用安全列表,您必须关闭 自动持久查询 (APQs)。APQs 允许客户端 在运行时注册任意操作,而安全列表则将操作限制为那些已经明确注册的操作。
要执行一个 操作,客户端可以提供其 PQL 规定的 ID 或完整的操作字符串。router 拒绝未注册的操作,如果 log_unknown
为 true,则这些 操作 将出现在您 router 的日志中。
💡 提示
在采用安全列表的同时,最好将 log_unknown
设置为 true
以便您可以监控 router 拒绝的操作。一旦您确信所有客户端都已正确配置,您可以将它关闭以减少日志中的噪音。
仅使用ID白名单
⚠️ 注意
不要从这个配置开始。它要求所有客户端必须通过提供他们的 PQL 规定的 ID 来执行操作。如果任何客户端仍然提供完整的操作字符串,则 router 将拒绝这些操作,即使它们包含在安全列表中。
使用以下配置,您的 router 拒绝所有操作字符串,只接受注册的操作 ID:
persisted_queries:enabled: truelog_unknown: truesafelist:enabled: truerequire_id: trueapq:enabled: false # APQ must be turned off
ⓘ 注意
要启用安全列表,您必须关闭 自动持久查询 (APQs)。APQs 允许客户端 在运行时注册任意操作,而安全列表则将操作限制为那些已经明确注册的操作。
如果您想使用此安全级别,您应该首先设置 允许操作字符串的安全列表。仅 ID 的安全列表要求所有您的客户端都通过 PQL 规定的 ID 执行操作,而不是通过操作字符串。在做出这些必要的更改时,您可以使用 router 中的更不限制性的 安全列表模式。
当 log_unknown
设置为 true 时,router 将记录所有被拒绝的操作,包括已经注册到您的 PQL 但使用了完整的操作字符串而不是 PQL 规定的 ID 的操作。
ⓘ 注意
在采用安全列表的同时,最好将 log_unknown
设置为 true
以便您可以监控 router 拒绝的操作。一旦您确信所有客户端都已正确配置,您可以将它关闭以减少日志中的噪音。
3. 操作注册
将操作注册到 PQL 有两个步骤:
- 使用针对客户端特定的工具生成持久查询清单 (PQM)
- 使用 Rover CLI 工具将 PQMs 发布到 PQL
将这两个步骤集成到 CI/CD 流程中,可以使您在发布新的客户端应用程序版本时自动执行新的操作。
3.1 生成持久的查询清单
一旦 PQL 存储GraphOS 中,客户端团队就可以开始向其中发布操作。要这样做,您必须为要发布的操作生成 JSON 清单。您为每个客户端应用程序生成一个单独的清单。
在 CI/CD 流程中执行清单生成,当您发布新的客户端应用程序版本时,会自动集成新操作。
生成方法
Apollo 客户端 为 Web、Kotlin 和 iOS 每个客户端都提供了从应用程序源生成清单文件的机制。Apollo 还支持由 Relay 编译器生成的清单。
ⓘ 注意
如果您的客户端应用程序使用其他的 GraphQL 客户端 库,您可以为生成操作清单构建自己的机制。查看期望的 清单格式。
查看您的客户端库的说明
Apollo 客户端 Web
在应用程序项目中,将
@apollo/generate-persisted-query-manifest
包作为开发依赖项安装:npm install --save-dev @apollo/generate-persisted-query-manifest此软件包包含一个命令行接口(CLI)命令,用于从您的应用程序源生成清单文件。
使用以下命令生成您的第一个清单:
npx generate-persisted-query-manifest- 如果命令成功执行,则您的清单将写入
persisted-query-manifest.json
。 - 如果命令执行失败(或者您的清单中没有包含所有预期的操作),您可以使用以下方式配置命令的行为描述 包的 README 文件 。
- 如果命令成功执行,则您的清单将写入
查看 Apollo 客户端持久化查询的完整指南以获取详细说明。
Apollo Kotlin
ⓘ 注意
清单的生成需要 Apollo Kotlin 3.8.2
或更高版本。
要使用 Apollo Kotlin 生成操作清单,您需要修改项目 Gradle 插件配置,以生成清单文件以及您操作的 Kotlin 标准源文件:
apollo {service("myapi") {packageName.set("com.example.myapi")operationManifestFormat.set("persistedQueryManifest")}}
清单将在 build/generated/manifest/apollo/myapi/persistedQueryManifest.json
查看 Apollo Kotlin 持久化查询的完整指南以获取详细说明。
Apollo iOS
ⓘ 注意
清单的生成需要 Apollo iOS 1.4.0
或更高版本。
要使用 Apollo iOS 生成操作清单,您可以使用与您的每个操作生成 Swift 代码相同的 代码生成引擎。具体来说,您需要修改引擎的文件输出配置以包括 operationManifest
的输出。
查阅完整的Apollo iOS持久化查询指南以获取详细说明。
Relay编译器
Rover CLI具有一个内置功能,可以发布由Relay编译器生成的操作清单。请参阅Relay的文档以获取有关生成清单的说明。
3.2 将清单发布到PQL
💡 提示
确保您的Rover CLI版本为0.17.2
或更高版本。先前的版本不支持将操作发布到PQL。下载最新版本。
在您生成操作清单后,可以使用Rover CLI将其发布到您的PQL,如下所示:
rover persisted-queries publish my-graph@my-variant \--manifest ./persisted-query-manifest.json
- 参数
my-graph@my-variant
是PQL连接的任何变体的graph ref
。- Graph refs具有以下格式
graph-id@variant-name
。
- Graph refs具有以下格式
- 使用
--manifest
选项提供要发布的清单的路径。
ⓘ 注意
命令persisted-queries publish
假定清单使用Apollo客户端工具生成的格式。该命令还可以支持由Relay编译器生成的清单,通过添加--manifest-format relay
参数。您的Rover CLI版本必须为0.19.0或更高版本才能使用此参数。
命令persisted-queries publish
执行以下操作:
将提供的清单文件中的所有操作发布到与指定变体或指定PQL链接的PQL中。
- 将清单发布到PQL是累加的。PQL中保留现有条目。
- 如果你在PQL中发布相同id但不同的详细信息操作,则整个发布命令会因为错误而失败。
更新PQL应用到的任何其他变体,以便与这些变体相关的路由器可以获取它们更新的PQL。
与生成清单一样,最好在CI/CD管道中执行此命令,将新操作作为应用程序发布过程的一部分。Rover提供的API密钥必须具有角色。Graph Admin或Persisted Query Publisher。Persisted Query Publisher是一个专为与rover persists queries publish
命令使用的特殊角色;具有此角色的API密钥无权访问GraphOS中的图形数据,适合与受信任的第三方客户端开发者共享,他们应允许发布您的图形的PQL操作,但不应有其他访问您的图形。
测试操作
你可以发送一些测试操作以测试是否已成功发布清单:
首先,启动您的GraphOS连接路由器:
APOLLO_KEY="..." APOLLO_GRAPH_REF="..." ./router --config ./router.yaml2023-05-11T15:32:30.684460Z INFO Apollo Router v1.18.1 // (c) Apollo Graph, Inc. // Licensed as ELv2 (https://go.apollo.dev/elv2)2023-05-11T15:32:30.684480Z INFO Anonymous usage data is gathered to inform Apollo product development. See https://go.apollo.dev/o/privacy for details.2023-05-11T15:32:31.507085Z INFO Health check endpoint exposed at http://127.0.0.1:8088/health2023-05-11T15:32:31.507823Z INFO GraphQL endpoint exposed at http://127.0.0.1:4000/ 🚀
接下来,使用curl
发送POST请求,如下所示:
curl https://127.0.0.1:4000 -X POST --json \'{"extensions":{"persistedQuery":{"version":1,"sha256Hash":"dc67510fb4289672bea757e862d6b00e83db5d3cbbcfb15260601b6f29bb2b8f"}}}'
如果您的路由器的PQL包含一个ID与提供的sha256Hash属性值匹配的操作,它将执行相应的操作并返回结果。
4. 客户端更新
当清单发布且路由器配置后,您可以更新您的客户端以使用已注册的操作ID。组织可以通过发布特定于客户端的PQMs到PQL一次更新一个客户端。
ⓘ 注意
此步骤提供了性能优势,但对于认证不是必需的。您可以在认证模式下继续使用完整的操作字符串而不是操作ID。
客户端可以使用用于自动持久查询(APQ)相同的协议来使用由PQL指定的ID执行操作。
以下是一个请求以ID执行操作的自定义内容:
{"variables": null,"extensions": {"persistedQuery": {"version": 1,"sha256Hash": "PQL_ID_HERE"}}}
💡 提示
如果执行包含GraphQL变量的操作,请使用variables
属性指定它们。
Apollo的移动客户端让您可以使用执行持久化查询操作的相同机制,就像APQs一样。有关实现细节,请参阅他们的持久化查询文档。
在使用 Apollo Client Web 时,通过ID发送持久化查询需要您使用额外的包,在运行时与@apollo/client
的内置createPersistedQueryLink
一起使用。Apollo Client Web需要此包以确保在运行时发送的ID与由generate-persisted-query-manifest
生成的ID匹配。移动客户端在格式化操作方面采用更加确定的策略,因此不需要额外的支持。
有关实现细节,请参阅 Apollo Client Web 的持久化查询文档。
渐进式采用路径
持久化查询的分级安全级别让您可以采用渐进式方法,而不仅仅是同时要求所有客户端通过已注册的操作ID发送请求。您可以按照以下步骤进行渐进式采用:
确定您想要实施持久化查询的第一个客户端。这可能是由您最习惯的客户端或团队,或最习惯于 GraphOS 的客户端。
遵循您选择客户端的实施步骤:
- 创建并链接一个PQL到预发布或开发变体。
- 在配置路由器时,从审计模式开始。
- 使用特定客户端的工具生成操作清单,并将其发布到PQL作为您客户端的CI/CD流程的一部分。
- (可选) 将您的选择客户端更新为仅使用已注册的操作,无论是通过完整的操作字符串还是操作ID。
- 与 Apollo Client Web 打工的团队需要在运行时使用额外的包以发送持久化查询。
继续监控您的路由器日志:一旦您一致地看到未注册的操作被记录,而注册的操作没有,那么您就已经为该客户端完成了设置! 🎉
如果你的目标是安全清单,那么你需要 协调多个客户团队 以完成每个客户应用的这些步骤。
一旦你的 路由器's> 日志完全清除了意外 操作,你可以配置你的路由器以使用 安全清单模式。然后,为了获取性能收益,更新你的客户端应用 以使用操作 ID 而不是全操作字符串。
一旦你确认所有客户端应用都使用 ID,你可以切换到最严格的安全级别: 仅使用 ID 的安全清单。此安全级别强制执行使用操作 ID 而不是全操作字符串的性能收益。如果你对持久查询的仅限安全性方面满意,且性能收益可选,不需要启用此功能。
协调客户团队
一旦你完成了一个客户的实施步骤,你可以协调所有客户团队
- 识别所有针对你的 路由器 运行 操作 的客户端应用以及那些应用使用的 GraphQL 客户端库。
- 在你启用路由器中的安全清单之前,你的客户端应用必须开始向你的 PQL 发布他们的 操作。
- 告知你的客户端开发团队,采用持久查询需要向他们的 CI/CD 管道添加工具。
- 具体来说,每个客户端团队将需要生成客户端 清单 并将清单发布到 PQL。
- 确定哪些团队成员将协助添加各自 CI/CD 管道中的工具。
指导每个客户端团队遵循实施步骤中 渐进式采用路径 介绍的步骤。
持久化查询列表管理
从 持久化查询列表 页面上,你可以通过点击任何 PQL 右侧的 操作 列下面的 ••• 菜单执行以下操作:
- 将列表作为 JSON 文件下载
- 发布 操作
- 更新 PQL 的名称和描述
- 链接和取消链接变体
- 完全删除 PQL
“发布操作” 操作提供了一个 Rover CLI 命令 来完成此操作。
操作管理
您可以使用Rover CLI将新操作添加到PQL中,并且可以从GraphOS Studio的PQL页面中删除操作。由于每个操作都应有一个唯一的ID,因此无法更新现有操作—如果尝试发布一个已存在操作ID的修订版操作,Rover将会返回错误。Rover CLI,操作ID,body
,
添加操作
要将新操作添加到PQL中,您需要使用Rover CLI发布更新的清单。除非您发布的清单中包括PQL中的该操作,否则不会从PQL中删除该操作。每次清单发布只会添加PQL中的任何新操作。
删除操作
如果您想删除操作,您必须从Studio删除。从“持久化查询列表”页面,点击一个持久化查询列表以打开它。然后,在特定操作旁边的“操作”列下面的•••菜单中选择“删除”。
您应该只删除有问题的操作且不应该执行。即使对于这样的操作,认识到操作删除可能导致您的igs应用错误对于合法用户来说也很重要,这取决于你的安全级别以及客户端是否发送完整的操作字符串或操作ID。
- 无论安全级别如何,如果客户端发送已被删除操作的操作ID,路由器将拒绝该操作。
- 如果您启用了whitelisting,路由器将拒绝从PQL删除但客户端仍在执行的操作,无论客户端是否发送操作ID或完整的操作字符串。
- 当路由器允许操作ID或处于审计模式允许操作ID modes,如果客户端发送已删除操作的完整操作字符串,路由器会执行它。
尽管您不能直接通过Studio UI撤销操作删除,但您始终可以使用Rover CLI重新发布已删除操作。
清单格式
ⓘ 注意
如果正在构建自己的工具来生成持久查询清单,则需要只阅读本节。
持久查询清单具有以下最小结构:
{"format": "apollo-persisted-query-manifest","version": 1,"operations": [{"id": "dc67510fb4289672bea757e862d6b00e83db5d3cbbcfb15260601b6f29bb2b8f","body": "query UniversalQuery { __typename }","name": "UniversalQuery","type": "query"}]}
清单属性在下面进行了文档说明。
顶级属性
属性 | 描述 |
---|---|
| 这个值当前总是 |
| 这个值当前总是 |
| 一个对象数组,描述了要发布的个别GraphQL 操作。 有关详细信息,请参阅每个操作的属性。 |
每个操作的属性
在说明的operations
数组中的每个条目都是一个JSON对象,描述了一个要发布的单个GraphQL 操作:
{"id": "dc67510fb4289672bea757e862d6b00e83db5d3cbbcfb15260601b6f29bb2b8f","body": "query UniversalQuery { __typename }","name": "UniversalQuery","type": "query"}
每个操作对象具有以下属性:
属性 | 描述 |
---|---|
| 您在PQL中操作的唯一ID。 此值必须在PQL中的操作中是唯一的。只要操作的 为了确保唯一性,工具应基于操作 |
| 操作 查询 文档的完整内容。包括操作本身的定义以及伴随的 片段定义。当客户端发送相应的ID或匹配的操作时,路由器会执行此字符串作为查询文档。有关详细信息,请参阅确保一致的操作文档。 |
| 操作 的名称。必须与 此值在PQL中的操作中不需要是唯一的。通常,不同的客户端会以具有相同名称的不同操作执行操作,并且每个操作都需要在PQL中有一个单独的条目。 |
| GraphQL操作的类型。始终是以下值之一:
|
生成ID
当为清单生成操作ID时,应使用每个操作独特的值,例如查询文档的crypto图形哈希。Apollo的清单生成工具使用文档SHA256哈希的base16表示形式,这与用于APQ的格式相同。
通过这种方式根据查询文档生成标识符,您确保不同的操作始终有不同的ID。ID的唯一性防止在您的PQL中出现意外的碰撞。它还允许路由器通过完整的操作字符串和PQL指定的ID执行操作。
⚠️ 注意
永远不要使用操作名作为其PQL ID。不同的客户端(或甚至是同一客户端的不同版本)可能使用相同的名称执行不同的操作,所有这些不同的操作都应该出现在您的PQL中。
确保操作文档的一致性
当启用安全名单的客户端向路由器发送操作字符串时,路由器会检查该操作字符串是否存在于其持久查询列表中。
当比较传入的自定义格式GraphQL文档和其PQL中注册的操作时,路由器会忽略一些没有语义影响的文档方面:例如,忽略空白、注释和逗号。
- 被忽略的标记,如空白、注释和逗号被忽略。
- 顶层定义(操作和片段定义)的顺序被忽略。这意味着当从操作和片段构建完整的GraphQL文档时,不需要确保片段在构建时间和运行时以相同的顺序放置。
然而,文档的所有其他细节必须匹配。例如,字段顺序、参数顺序、$variable
名称、别名名称、字符串和数字文字以及__typename
字段的存在必须匹配传入的自定义格式GraphQL文档和持久查询列表中的文档。
ⓘ 注意
在Router v1.28之前,安全名单要求传入的文档与安全名单中的文档精确匹配,包括空白、注释和顶级定义顺序。
例如,大多数应用程序将以下查询的响应同等对待,但 路由器 会拒绝客户端操作,因为它不完全符合 PQL 条目。(操作在语义上确实不同,因为 GraphQL 服务器 以请求的顺序返回字段,尽管大多数应用程序忽略了 JSON 中对象字段 的顺序。)
query GetBooks {books {publishDatetitle}}
query GetBooks {books {titlepublishDate}}
除了顶级定义的顺序之外,注册的操作与客户端发送的操作之间的顺序差异也会导致 路由器 拒绝客户端操作,即使它们对操作没有语义影响。
query GetBooks($limit: Int, $offset: Int) {books(limit: $limit, offset: $offset) {title}}
query GetBooks($limit: Int, $offset: Int) {books(offset: $offset, limit: $limit) {title}}
ⓘ 注意
路由器忽略顶级定义的顺序和忽略的标记,以便更容易构建生成持久化查询清单的工具,该清单的内容与在运行时发送的内容匹配。如果您的用例需要在比较传入机会与白名单时应用进一步的 标准化 步骤,请联系 Apollo 支持;我们愿意添加更多标准化作为可选择的特性。
为了确保您正确生成清单条目,请注意,您的应用程序的客户端库可能在对源中定义的操作执行相应的操作之前修改这些操作字符串。例如,默认情况下,所有 Apollo Client 库都会给查询中的每个对象添加 __typename
字段,如果该字段已存在的话:
query GetBooks {books {authortitle}}
query GetBooks {books {authortitle__typename}}
ⓘ 注意
适用于 Apollo Client 库的清单生成工具都会考虑这种默认行为。
如果您正在构建自己的清单生成工具,请确保它考虑了您选择客户端库中的任何此类 操作 变更。否则,如果启用了白名单,路由器将拒绝您的应用程序操作,因为操作字符串不匹配。
同样,如果您的客户端通过提供其 PQL 指定的 ID 执行操作,则在您未考虑这些操作变更的情况下,它们可能会执行未添加客户端库增强操作的操作。