Używanie pakietu Admin SDK z usługą Data Connect

Firebase Admin SDK to zestaw bibliotek serwera, które umożliwiają interakcję z Firebase w środowiskach uprzywilejowanych w celu wykonywania działań takich jak zapytania i mutacje w Firebase Data Connect w ramach zbiorczego zarządzania danymi oraz innych operacji z użyciem podwyższonych uprawnień i podszytych danych logowania.

Admin SDK udostępnia interfejs API do wywoływania operacji w trybach odczytu/zapisu i tylko do odczytu. Operacje tylko do odczytu zapewniają spokój ducha, ponieważ umożliwiają wdrażanie funkcji administracyjnych, które nie mogą modyfikować danych w bazach danych.

Konfiguracja pakietu Admin SDK

Aby zacząć korzystać z Firebase Data Connect na serwerze, musisz najpierw zainstalować i skonfigurować Admin SDK dla Node.js.

Inicjowanie pakietu Admin SDK w skryptach

Aby zainicjować pakiet SDK, zaimportuj rozszerzenia Data Connect i zadeklaruj identyfikator usługi projektu oraz lokalizację.


import { initializeApp } from 'firebase-admin/app';
import { getDataConnect } from 'firebase-admin/data-connect';

// If you'd like to use OAuth2 flows and other credentials to log in,
// visit https://firebase.google.com/docs/admin/setup#initialize-sdk
// for alternative ways to initialize the SDK.

const app = initializeApp();

const dataConnect = getDataConnect({
    serviceId: 'serviceId',
    location: 'us-west2'
});

Projektowanie zapytań i mutacji do użycia z Admin SDK

Admin SDK jest przydatny do przeprowadzania operacji Data Connect, biorąc pod uwagę te kwestie:

Poznaj pakiet SDK i @auth(level: NO_ACCESS) dyrektywę operacji.

Ponieważ Admin SDK działa z uprawnieniami, może wykonywać wszystkie Twoje zapytania i mutacje niezależnie od poziomów dostępu ustawionych za pomocą @auth dyrektyw, w tym na poziomie NO_ACCESS.

Jeśli oprócz operacji na klientach organizujesz zapytania administracyjne i mutacje w .gql plikach źródłowych do importowania do skryptów administracyjnych, Firebase zaleca oznaczanie operacji administracyjnych bez żadnego poziomu dostępu do autoryzacji lub bardziej wyraźne ustawianie ich jako NO_ACCESS. W obu przypadkach uniemożliwia to wykonywanie takich operacji przez klientów lub w innych kontekstach bez uprawnień.

Używanie pakietu SDK z emulatorem Data Connect

W środowiskach prototypowych i testowych może być przydatne wypełnianie danych i wykonywanie innych operacji na danych lokalnych. Flaga Admin SDK upraszcza przepływy pracy, ponieważ może ignorować uwierzytelnianie i autoryzację w przypadku przepływów lokalnych. (Możesz też wyraźnie zgodzić się na przestrzeganie konfiguracji uwierzytelniania i autoryzacji operacji z podszywaniem się pod użytkownika).

Pakiety Firebase Admin SDK automatycznie łączą się z Data Connectemulatorem, gdy ustawiona jest zmienna środowiskowa DATA_CONNECT_EMULATOR_HOST:

export DATA_CONNECT_EMULATOR_HOST="127.0.0.1:9399"

Aby dowiedzieć się więcej, zobacz:

Uruchamianie operacji administracyjnych

Admin SDK jest zapewniana w przypadku operacji uprzywilejowanych na Twoich danych o znaczeniu krytycznym.

Pakiet Admin SDK udostępnia 3 zestawy interfejsów API:

  • Wygenerowane pakiety Admin SDK, czyli pakiety SDK bezpieczne pod względem typów, które są generowane z Twoich gqldefinicji w taki sam sposób jak pakiety SDK klienta.
  • Ogólny interfejs do uruchamiania dowolnych operacji GraphQL, w którym kod implementuje zapytania i mutacje oraz przekazuje je do metody odczytu i zapisu executeGraphql lub metody tylko do odczytu executeGraphqlRead.
  • Specjalistyczny interfejs do operacji na danych zbiorczych, który zamiast ogólnych metod executeGraphql udostępnia dedykowane metody operacji modyfikacji: insert, insertMany, upsertupsertMany.

Zarządzanie danymi za pomocą wygenerowanych pakietów SDK

Generujesz pakiety SDK administratoragql definicji w taki sam sposób, jak pakiety SDK klienta.

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.

Zarządzanie danymi za pomocą metod executeGraphql

Jeśli chcesz wykonać jednorazowe operacje, dla których nie masz zdefiniowanych gqlmutacji ani zapytań, możesz użyć metody executeGraphql lub metody executeGraphqlRead tylko do odczytu.

Odgrywanie roli nieautoryzowanego użytkownika

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, którego tożsamość została przejęta (patrz następna sekcja), lub jako użytkownik, którego tożsamość została przejęta, ale nie został on uwierzytelniony. Nieuwierzytelnieni użytkownicy mogą wykonywać tylko operacje oznaczone jakoPUBLIC.

// Query to get posts, with authentication level PUBLIC
const queryGetPostsImpersonation = `
    query getPosts @auth(level: PUBLIC) {
        posts {
          description
        }
    }`;

// Attempt to access data as an unauthenticated user
const optionsUnauthenticated: GraphqlOptions<undefined> = {
    impersonate: {
        unauthenticated: true
    }
};

// executeGraphql with impersonated unauthenticated user scope
const gqlResponse = await dataConnect.executeGraphql<UserData, undefined>(queryGetPostsImpersonation, optionsUnauthenticated);

Podszywanie się pod użytkownika

Istnieją też przypadki, w których chcesz, aby skrypty modyfikowały dane użytkownika na podstawie ograniczonych danych logowania w imieniu konkretnego użytkownika. To podejście jest zgodne z zasadą jak najmniejszych uprawnień.

Aby korzystać z tego interfejsu, zbierz informacje z dostosowanego tokena uwierzytelniania JWT, który jest zgodny z Authenticationformatem tokena. Zapoznaj się też z przewodnikiem po tokenach niestandardowych.

// Get the current user's data
const queryGetUserImpersonation = `
    query getUser @auth(level: USER) {
        user(key: {uid_expr: "auth.uid"}) {
            id,
            name
        }
    }`;

// Impersonate a user with the specified auth claims
const optionsAuthenticated: GraphqlOptions<undefined> = {
    impersonate: {
        authClaims: {
            sub: 'QVBJcy5ndXJ1'
        }
    }
};

// executeGraphql with impersonated authenticated user scope
const gqlResponse = await dataConnect.executeGraphql<UserData, undefined>(queryGetUserImpersonation, optionsAuthenticated);

// gqlResponse -> { "data": { "user": { "id": "QVBJcy5ndXJ1", "name": "Fred" } } }

Używanie danych logowania administratora

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

// User can be publicly accessible, or restricted to admins
const query = "query getProfile(id: AuthID) { user(id: $id) { id name } }";

interface UserData {
  user: {
    id: string;
    name: string;
  };
}

export interface UserVariables {
  id: string;
}

const options:GraphqlOptions<UserVariables> = { variables: { id: "QVBJcy5ndXJ1" } };

// executeGraphql
const gqlResponse = await dataConnect.executeGraphql<UserData, UserVariables>(query, options);

// executeGraphqlRead (similar to previous sample but only for read operations)
const gqlResponse = await dataConnect.executeGraphqlRead<UserData, UserVariables>(query, options);

// gqlResponse -> { "data": { "user": { "id": "QVBJcy5ndXJ1", "name": "Fred" } } }

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.

Wykonywanie operacji zbiorczych na danych

W przypadku operacji na danych zbiorczych w bazach danych produkcyjnych Firebase zaleca używanie Admin SDK.

Pakiet SDK udostępnia te metody pracy z danymi zbiorczymi. Na podstawie podanych argumentów każda metoda tworzy i wykonuje mutację GraphQL.


// Methods of the bulk operations API
// dc is a Data Connect admin instance from getDataConnect

const resp = await dc.insert("movie" /*table name*/, data[0]);
const resp = await dc.insertMany("movie" /*table name*/, data);
const resp = await dc.upsert("movie" /*table name*/, data[0]);
const resp = await dc.upsertMany("movie" /*table name*/, data);

Uwagi dotyczące skuteczności operacji zbiorczych

Każde żądanie do backendu powoduje jedną podróż w obie strony do Cloud SQL, więc im więcej żądań zbiorczych, tym większa przepustowość.

Im większy rozmiar partii, tym dłuższe jest wygenerowane polecenie SQL. Gdy zostanie osiągnięty limit długości polecenia SQL w PostgreSQL, pojawi się błąd.

W praktyce eksperymentuj, aby znaleźć odpowiedni rozmiar partii dla swojego obciążenia.

Co dalej?