使用產生的 Admin SDK

Firebase Data Connect 管理員 SDK 可讓您從受信任的環境 (例如 Cloud Functions、自訂後端或自己的工作站) 呼叫查詢和突變。與為用戶端應用程式產生 SDK 的方式大致相同,您可以在設計要部署至 Data Connect 服務的結構定義、查詢和變動時,平行產生自訂管理員 SDK。然後,將這個 SDK 的方法整合到後端邏輯或管理指令碼中。

如先前所述,請務必注意,系統不會在提出要求時,由用戶端提交 Data Connect 查詢和變動。部署後,資料連結作業會儲存在伺服器上,例如 Cloud Functions。也就是說,每當您將變更部署至查詢和突變時,也需要重新產生管理員 SDK,並重新部署任何依賴這些 SDK 的服務。

事前準備

產生 Admin SDK

建立 Data Connect 結構定義、查詢和變動後,即可產生對應的管理 SDK:

  1. 開啟或建立 connector.yaml 檔案,並新增 adminNodeSdk 定義:

    connectorId: default
    generate:
      adminNodeSdk:
        outputDir: ../../dataconnect-generated/admin-generated
        package: "@dataconnect/admin-generated"
        packageJsonDir: ../..
    

    connector.yaml 檔案通常與包含查詢和變動定義的 GraphQL (.gql) 檔案位於同一目錄。如果您已產生用戶端 SDK,系統會建立這個檔案。

  2. 產生 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 權杖,代表特定使用者執行作業;至少必須在子項聲明中指定使用者的使用者 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 SDKverifyIdToken 方法驗證及解碼驗證權杖。舉例來說,假設您的端點是以純 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) 指令定義。這麼做可確保只有管理員層級的呼叫者可以執行這些作業。