Korzystanie z wygenerowanych pakietów Admin SDK

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

Jak wspomnieliśmy w innym miejscu, ważne jest, aby pamiętać, że zapytania Data Connect i mutacje nie są przesyłane przez klientów w momencie wysyłania żądania. Zamiast tego po wdrożeniu operacje Data Connect są przechowywane na serwerze, tak jak 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

  • Dowiedz się więcej o projektowaniu schematów, zapytań i mutacji Data Connect. W typowym procesie będziesz je rozwijać równolegle z kodem aplikacji, w tym z usługami, które korzystają z pakietów Admin SDK.
  • Zainstaluj wiersz poleceń Firebase.

  • Dołącz pakiet Admin SDK dla Node.js jako zależność wszędzie tam, gdzie planujesz wywoływać wygenerowane pakiety Admin SDK.

Generowanie pakietów Admin SDK

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

  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), które zawierają 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, gdy zaktualizujesz pliki 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 } }
);

Podszywanie się pod nieuwierzytelnionego użytkownika

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

Gdy uruchamiasz operacje publiczne za pomocą pakietu Admin SDK, unikaj uruchamiania operacji z pełnymi uprawnieniami administratora (zgodnie z zasadą najmniejszych uprawnień). Zamiast tego uruchom operację jako użytkownik, pod którego się podszywasz (patrz następna sekcja), lub jako nieuwierzytelniony użytkownik, pod którego się podszywasz. Nieuwierzytelnieni użytkownicy mogą uruchamiać tylko operacje oznaczone jako PUBLIC.

W powyższym przykładzie zapytanie getSongs jest wykonywane jako nieuwierzytelniony użytkownik.

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 określić 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 Data Connect operacjach GraphQL).

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

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

W przypadku korzystania z wywoływalnych Cloud Functions token uwierzytelniania jest automatycznie weryfikowany i możesz go używać tak 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 pakietu 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 Authenticationzostał 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 } }
    );

    // ...
});

Tylko podczas wykonywania prawdziwych zadań administracyjnych, takich jak migracja danych, w bezpiecznym środowisku niedostępnym publicznie, należy określić identyfikator użytkownika, który nie pochodzi z weryfikowalnego źródła:

// 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, które mają być używane tylko do celów administracyjnych, zdefiniuj je za pomocą dyrektywy @auth(level: NO_ACCESS). Dzięki temu tylko osoby wywołujące z uprawnieniami administratora będą mogły wykonywać te operacje.