Korzystanie z wygenerowanych pakietów Admin SDK

Pakiety SDK administratora Firebase Data Connect umożliwiają wywoływanie zapytań i mutacji w zaufanych środowiskach, takich jak Cloud Functions, niestandardowe backendy czy własna stacja robocza. Podobnie jak w przypadku generowania pakietów SDK dla aplikacji klienckich możesz równolegle generować niestandardowy pakiet SDK administratora podczas projektowania schematów, zapytań i mutacji, które wdrażasz w usłudze Data Connect. Następnie zintegruj metody z tego pakietu SDK z logiką backendu lub skryptami administracyjnymi.

Jak już wspominaliśmy, warto pamiętać, że zapytania i mutacje Data Connect nie są przesyłane przez klientów w momencie wysłania żądania. Zamiast tego po wdrożeniu operacje Data Connect są przechowywane na serwerze, np. w Cloud Functions. Oznacza to, że za każdym razem, gdy wdrażasz zmiany w zapytaniach i mutacjach, musisz też ponownie wygenerować pakiety Admin SDK i ponownie wdrożyć wszystkie usługi, które z nich korzystają.

Zanim zaczniesz

Generowanie pakietów SDK administratora

Po utworzeniu schematów, zapytań i mutacji Data Connect możesz wygenerować odpowiedni pakiet SDK administratora:

  1. Otwórz lub utwórz plik connector.yaml i dodaj definicję adminNodeSdk:

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

    Plik connector.yaml zwykle znajduje się w tym samym katalogu co pliki GraphQL (.gql) zawierające definicje zapytań i mutacji. Jeśli masz już wygenerowane pakiety SDK klienta, ten plik został już utworzony.

  2. Wygeneruj pakiet SDK.

    Jeśli masz zainstalowane rozszerzenie Data Connect VS Code, będzie ono zawsze aktualizować wygenerowane pakiety SDK.

    W przeciwnym razie użyj wiersza poleceń Firebase:

    firebase dataconnect:sdk:generate

    Możesz też automatycznie ponownie generować pakiety SDK po zaktualizowaniu plików gql:

    firebase dataconnect:sdk:generate --watch

Wykonywanie operacji z pakietu Admin SDK

Wygenerowany pakiet Admin SDK zawiera interfejsy i funkcje odpowiadające definicjom gql, których możesz używać do wykonywania operacji na bazie danych. Załóżmy na przykład, że wygenerowano pakiet SDK dla bazy danych utworów wraz z zapytaniem 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 } }
);

Możesz też określić konfigurację łącznika:

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 } }
);

Odgrywanie roli nieautoryzowanego użytkownika

Pakiety Admin SDK są przeznaczone do uruchamiania w zaufanych środowiskach, dlatego mają nieograniczony dostęp do Twoich baz danych.

Podczas wykonywania operacji publicznych za pomocą pakietu Admin SDK unikaj wykonywania operacji z pełnymi uprawnieniami administratora (zgodnie z zasadą najmniejszych uprawnień). Zamiast tego uruchom operację jako użytkownik z uprawnieniami do personifikacji (patrz następna sekcja) lub jako użytkownik z uprawnieniami do personifikacji bez uwierzytelniania. Nieuwierzytelnieni użytkownicy mogą wykonywać tylko operacje oznaczone symbolem PUBLIC.

W przykładzie powyżej zapytanie getSongs jest wykonywane jako zapytanie użytkownika bez uwierzytelnienia.

Podszywanie się pod użytkownika

Możesz też wykonywać operacje w imieniu konkretnych użytkowników, przekazując część lub całość tokena Firebase Authentication w opcji impersonate. Musisz co najmniej podać identyfikator użytkownika w roszczeniu sub. (Jest to ta sama wartość co auth.uid wartość serwera, do której możesz się odwoływać w operacjach Data Connect GraphQL).

Gdy podszywasz się pod użytkownika, operacja zakończy się powodzeniem tylko wtedy, gdy podane przez Ciebie dane użytkownika przejdą testy uwierzytelniania określone w definicji GraphQL.

Jeśli wywołujesz wygenerowany pakiet SDK z publicznie dostępnego punktu końcowego, konieczne jest, aby punkt końcowy wymagał uwierzytelniania i aby przed użyciem tokena uwierzytelniającego do podszywania się pod użytkownika sprawdzić jego integralność.

Gdy używasz funkcji wywoływanej Cloud Functions, token uwierzytelniania jest weryfikowany automatycznie i możesz go używać jak w tym przykładzie:

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 } }
    );

    // ...
});

W przeciwnym razie użyj metody verifyIdToken usługi Admin SDK, aby zweryfikować i zdekodować token uwierzytelniania. Załóżmy na przykład, że punkt końcowy jest zaimplementowany jako zwykła funkcja HTTP, a token Firebase Authentication został przekazany do punktu końcowego za pomocą nagłówka authorization, zgodnie ze standardem:

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 } }
    );

    // ...
});

Identyfikator użytkownika, który nie pochodzi z weryfikowalnego źródła, należy podawać tylko podczas wykonywania prawdziwych zadań administracyjnych, takich jak migracja danych, w bezpiecznym środowisku, które nie jest publicznie dostępne:

// Never do this if end users can initiate execution of the code!
const favoriteSongs = await getMyFavoriteSongs(
  undefined,
  { impersonate: { authClaims } }
);

Uruchamianie z nieograniczonym dostępem

Jeśli wykonujesz operację, która wymaga uprawnień administratora, pomiń parametr impersonate w wywołaniu:

await upsertSong(adminDc, {
  title: songTitle_one,
  instrumentsUsed: [Instrument.VOCAL],
});

Operacja wywołana w ten sposób ma pełny dostęp do bazy danych. Jeśli masz zapytania lub mutacje przeznaczone wyłącznie do celów administracyjnych, zdefiniuj je za pomocą dyrektywy @auth(level: NO_ACCESS). Dzięki temu tylko osoby wywołujące na poziomie administratora mogą wykonywać te operacje.