借助 Firebase Data Connect Admin SDK,您可以从可信的环境(例如 Cloud Functions、自定义后端或您自己的工作站)调用查询和突变。与为客户端应用生成 SDK 的方式非常相似,您可以在设计部署到 Data Connect 服务的架构、查询和突变时,并行生成自定义 Admin SDK。然后,将此 SDK 中的方法集成到后端逻辑或管理脚本中。
正如我们在其他地方提到的,请务必注意,Data Connect 查询和突变不是由客户端在请求时提交的。相反,在部署时,数据连接操作会像 Cloud Functions 一样存储在服务器上。这意味着,每当您部署对查询和突变的更改时,还需要重新生成 Admin SDK 并重新部署依赖于这些 SDK 的任何服务。
准备工作
- 了解如何设计 Data Connect 架构、查询和变更。 在典型的工作流程中,您将与应用代码(包括使用 Admin SDK 的任何服务)并行开发这些测试。
- 安装 Firebase CLI。
- 在您计划调用生成的 Admin SDK 的任何位置,将 Node.js 版 Admin SDK 作为依赖项包含在内。
生成 Admin SDK
创建 Data Connect 架构、查询和 mutation 后,您可以生成相应的 Admin SDK:
打开或创建
connector.yaml文件,然后添加adminNodeSdk定义:connectorId: default generate: adminNodeSdk: outputDir: ../../dataconnect-generated/admin-generated package: "@dataconnect/admin-generated" packageJsonDir: ../..connector.yaml文件通常与包含查询和突变定义的 GraphQL (.gql) 文件位于同一目录中。如果您已生成客户端 SDK,则此文件已创建。生成 SDK。
如果您安装了 Data Connect VS Code 扩展程序,该扩展程序将始终保持生成的 SDK 为最新版本。
否则,请使用 Firebase CLI:
firebase dataconnect:sdk:generate或者,如需在更新
gql文件时自动重新生成 SDK,请执行以下操作:firebase dataconnect:sdk:generate --watch
通过 Admin SDK 执行操作
生成的 Admin SDK 包含与 gql 定义对应的接口和函数,您可以使用这些接口和函数对数据库执行操作。例如,假设您为歌曲数据库生成了一个 SDK,其中包含一个查询 getSongs:
import { initializeApp } from "firebase-admin/app";
import { getSongs } from "@dataconnect/admin-generated";
const adminApp = initializeApp();
const songs = await getSongs(
{ limit: 4 },
{ impersonate: { unauthenticated: true } }
);
或者,如需指定连接器配置,请执行以下操作:
import { initializeApp } from "firebase-admin/app";
import { getDataConnect } from "firebase-admin/data-connect";
import {
connectorConfig,
getSongs,
} from "@dataconnect/admin-generated";
const adminApp = initializeApp();
const adminDc = getDataConnect(connectorConfig);
const songs = await getSongs(
adminDc,
{ limit: 4 },
{ impersonate: { unauthenticated: true } }
);
模拟未经过身份验证的用户
Admin SDK 旨在从可信环境中运行,因此可以不受限制地访问您的数据库。
使用 Admin SDK 运行公开操作时,应避免使用完整的管理员权限(遵循最低权限原则)。您应以模拟用户(请参阅下一部分)或模拟未经身份验证的用户的身份运行该操作。未经身份验证的用户只能运行标记为 PUBLIC 的操作。
在上面的示例中,getSongs 查询是以未经身份验证的用户身份执行的。
模拟用户
您还可以通过在 impersonate 选项中传递部分或全部 Firebase Authentication 令牌来代表特定用户执行操作;至少,您必须在 sub 声明中指定用户的用户 ID。(此值与您可以在 Data Connect GraphQL 操作中引用的 auth.uid 服务器值相同。)
当您模拟用户时,只有在您提供的用户数据通过 GraphQL 定义中指定的身份验证检查后,操作才会成功。
如果您从可公开访问的端点调用生成的 SDK,则至关重要的是,该端点必须要求进行身份验证,并且您必须先验证身份验证令牌的完整性,然后才能使用该令牌来模拟用户。
使用可调用函数 Cloud Functions 时,系统会自动验证身份验证令牌,您可以按以下示例所示的方式使用该令牌:
import { HttpsError, onCall } from "firebase-functions/https";
export const callableExample = onCall(async (req) => {
const authClaims = req.auth?.token;
if (!authClaims) {
throw new HttpsError("unauthenticated", "Unauthorized");
}
const favoriteSongs = await getMyFavoriteSongs(
undefined,
{ impersonate: { authClaims } }
);
// ...
});
否则,请使用 Admin SDK 的 verifyIdToken 方法来验证和解码身份验证令牌。例如,假设您的端点实现为纯 HTTP 函数,并且您已使用 authorization 标头将 Firebase Authentication 令牌传递给端点(这是标准做法):
import { getAuth } from "firebase-admin/auth";
import { onRequest } from "firebase-functions/https";
const auth = getAuth();
export const httpExample = onRequest(async (req, res) => {
const token = req.header("authorization")?.replace(/^bearer\s+/i, "");
if (!token) {
res.sendStatus(401);
return;
}
let authClaims;
try {
authClaims = await auth.verifyIdToken(token);
} catch {
res.sendStatus(401);
return;
}
const favoriteSongs = await getMyFavoriteSongs(
undefined,
{ impersonate: { authClaims } }
);
// ...
});
只有在从安全且非公开访问的环境中执行真正意义上的管理任务(例如数据迁移)时,您才应指定并非来自可验证来源的用户 ID:
// Never do this if end users can initiate execution of the code!
const favoriteSongs = await getMyFavoriteSongs(
undefined,
{ impersonate: { authClaims } }
);
以不受限的访问权限运行
如果您要执行需要管理员级权限的操作,请从调用中省略 impersonate 参数:
await upsertSong(adminDc, {
title: songTitle_one,
instrumentsUsed: [Instrument.VOCAL],
});
以这种方式调用的操作具有对数据库的完整访问权限。如果您有仅用于管理目的的查询或突变,则应使用 @auth(level: NO_ACCESS) 指令定义它们。这样做可确保只有管理员级调用者才能执行这些操作。