概述
让我们整理一下关于如何在超级图形中实施身份验证的学习内容。在本课中,我们将:
- 配置 GraphOS 路由器将 HTTP 标头传递到 子图形上
- 设置 子图形以接收标头和验证用户
- 测试一个 查询,该查询需要使用 GraphOS Studio进行身份验证和授权
✅ 服务检查
在继续之前,让我们确保所有进程仍在运行!
- 应运行一个终端
npm start
,启动位于端口4001
上 subgragh 服务器的单体 子图服务器 - 另一个应该运行
npm run launch
,在端口4010
和4011
上启动单体目录中的服务。
✏️ 下载路由器
打开一个新的终端窗口,并导航到
router
目录。通过在终端中运行以下命令下载 GraphOS 路由器:
routercurl -sSL https://router.apollo.dev/download/nix/v1.46.0 | sh注意:访问官方文档来 探索路由器下载的备用方法。
现在,当我们检查
router
目录的内容时,我们会发现我们也有一个新文件,也称为router
!📦 router┣ 📄 router┣ 📄 router-config.yaml┗ 📄 supergraph-config.yaml我们应该做的最后一项更改。我们最初将图表中环境变量存储在
.env
文件中的单体目录中,以便我们轻松地回溯它们。我们将继续引用存储在.env
文件中的 变量,因为我们与 路由器一起工作,所以让我们 移动该文件从单体目录进入router
目录。📦 router┣ 📄 .env┣ 📄 router┣ 📄 router-config.yaml┗ 📄 supergraph-config.yaml
路由器的配置文件
在启动 router之前,让我们来了解其配置文件。在 router-config.yaml
中,我们会发现已经指定了一个配置选项:
include_subgraph_errors:all: true # Propagate errors from all subgraphs
默认情况下,subgraph出于安全原因,从 router日志中省略了错误。我们在配置文件中引用的设置 include_subgraph_errors
router在与 subgraphs进行通信时共享任何错误详细信息的设置。通过将 all
键设置为 true
,我们告诉 router我们希望了解在我们 全部 subgraphs中发生的错误。
这对于开发很有用,因为它将帮助我们解决在此过程中出现的所有问题!
✏️ 添加 Authorization
标头
注意:在超图中实施身份验证还有其他方法,例如在架构中使用授权指令、使用协处理器或使用 JWT 身份验证插件。在本课程中,我们将专注于子图中使用标头传播的身份验证。你可以组合策略来处理许多身份验证要求和实践“纵深防御”。有关这些方法的更多信息,请查看此 Apollo 技术说明。
让我们为路由器的router-config.yaml
文件添加另一个配置选项。
我们希望告诉路由器向其子图发送Authorization
标头,并包含每个请求。
headers:all:request:- propagate:named: "Authorization"
让我们分解这些新行做什么。
的
headers
键是我们设置所有 HTTP 标头规则的位置。all
表示嵌套在下面的规则将应用于所有的子图上。我们可以使用subgraphs
键指定哪些,但我们知道对于 Airlock,我们需要将它传递给所有子图。request
指定包含的头应该应用于 路由器接收的请求。最后,我们希望将
Authorization
头传递给所有 子图,所以我们将使用propagate
键,然后用named: 'Authorization'
指出头的名称。
注意:你可以 参阅 Apollo 文档,进一步了解传递哪些 HTTP 头的其他方式。
我们的 路由器已全部设置好,将这些身份验证头传递给其 子图,让我们确保子图准备好接收这些头并将其传递给自身的 解析器!
为身份验证设置子图
好消息是,整体 子图已经为身份验证设置好了!
还记得整体 subgraph还是一个独立的 GraphQL 服务器的时候吗?嗯,它已经采用 Authorization
头,使用账户服务检索用户令牌并验证它!
我们看看代码中的这个逻辑。
打开 monolith/index.js
文件,我们的整体 子图服务器。向下滚动到启动服务器的位置,我们可以找到 context
属性并查看该逻辑:
context: async ({ req }) => {const token = req.headers.authorization || "";const userId = token.split(" ")[1]; // get the user name after 'Bearer 'let userInfo = {};if (userId) {const { data } = await axios.get(`https://127.0.0.1:4011/login/${userId}`).catch((error) => {throw AuthenticationError();});userInfo = { userId: data.id, userRole: data.role };}const { cache } = server;return {...userInfo,dataSources: {bookingsDb: new BookingsDataSource(),reviewsDb: new ReviewsDataSource(),listingsAPI: new ListingsAPI({cache}),accountsAPI: new AccountsAPI({cache}),paymentsAPI: new PaymentsAPI({cache}),},};},
有了这个逻辑,我们不必在 index.js
文件中做任何额外的工作!
使用配置运行路由器
让我们运行 路由器。
在新终端中,导航到
路由器
目录。要启动 路由器,我们将键入我们的
APOLLO_KEY
和APOLLO_GRAPH_REF
。(记住,您可以在.env
文件中找到这些 变量!)然后,使用./router
启动 路由器,最后添加--config
标志以及router-config.yaml
文件的路径。routerAPOLLO_KEY=<APOLLO_KEY> APOLLO_GRAPH_REF=<APOLLO_GRAPH_REF> ./router --config router-config.yaml我们应该会在终端中看到输出消息,其中我们的 路由器 在
127.0.0.1:4000
处运行。
记住端口 4000
是最初的单体 GraphQL 服务器 运行的位置?现在我们已经成功地用 路由器 替换了它!客户端无需采取任何额外操作来更改其端点,它们可以像往常一样继续 查询。
👩🏽🔬 测试 认证
标头
让我们试一试!我们可以回到 Studio 中的 Explorer 来测试 查询 以进行 路由。
我们将尝试 查询,该 查询 需要认证且授权的用户:检索房东的房源。此 查询 需要您以房东身份登录。
通过 Explorer,我们来构建一个查询来检索宿主的房源信息。对于每个房源信息,我们都会请求其标题
、每晚价格
、描述
、缩略图
、床位数
以及房源类型
。
query GetHostListings {hostListings {titlecostPerNightdescriptionphotoThumbnailnumOfBedslocationType}}
让我们运行此查询,等等!出现AuthenticationError
,提示未登录用户😱
慌乱一阵后,让我们重新思考一下遗漏的部分。
我们刚刚设置了授权头作为服务器端处理,但实际上并没有发送与请求关联的头。因此,我们的服务器试图对发送请求的用户进行身份验证,但找不到该用户,接着返回了相应的错误。
让我们继续添加这些头。在 Explorer 的底部面板中,打开Headers
选项卡。
点击新建头并将头键设置为Authorization
。将值设置为Bearer user-1
。我们知道user-1
是宿主!
Authorization: Bearer user-1
让我们再次运行此查询!我们获得了所请求的列表,其中包含我们所需的所有字段。
我们收到ForbiddenError
,显示只有宿主有权访问房源信息 - 我们作为访客登录,非常棒,我们的服务器正在按预期运行!
练习
headers:all:request:- propagate:named: "airlock-cookie"
config.yaml
文件中,propagate
键会通知路由器执行什么操作?要点
- 要从路由器向下传递授权标头到其子图,我们需要设置路由器的配置文件。
- 在配置文件中,我们可以设置
headers
属性,并使用propagate
属性。
- 在配置文件中,我们可以设置
- 一个子图可以通过其
ApolloServer
构造函数的context
属性从路由器访问授权(和其他请求)标头。 - 我们可以使用 Apollo Explorer 的标头面板为我们的GraphQL请求设置授权标头。
下一步
我们在迁移计划中又完成了一项任务,我们准备继续进一步分离这个子图。
分享你关于本课程的问题和评论
你的反馈有助于我们改进!如果你遇到障碍或困惑,请告诉我们,我们会帮你的。所有评论都是公开的,并且必须遵守 Apollo 行为准则。请注意,已解决或已处理的评论可能会被移除。
你需要一个 GitHub 账户才能在下面发帖。没有一个? 转而在我们的 Odyssey 论坛发帖。