Używanie pakietu Admin SDK z SQL Connect

Pakiet Firebase Admin SDK to zestaw bibliotek serwerowych, które umożliwiają interakcję z Firebase w środowiskach z uprawnieniami. Możesz wykonywać takie działania jak wysyłanie zapytań i mutacji do usługi Firebase SQL Connect w celu zbiorczego zarządzania danymi oraz inne operacje z podwyższonymi uprawnieniami i odgrywaniem roli innego użytkownika.

Pakiet Admin SDK udostępnia interfejs API do wywoływania operacji w trybie odczytu/zapisu i w trybie „tylko do odczytu”. Dzięki operacjom tylko do odczytu możesz spokojnie implementować funkcje administracyjne, które nie mogą modyfikować danych w Twoich bazach danych.

Konfiguracja pakietu Admin SDK

Aby zacząć korzystać z pakietu Admin SDK z usługą Firebase SQL Connect na serwerze, musisz najpierw zainstalować i skonfigurować pakiet Admin SDK dla Node.js.

Inicjowanie pakietu Admin SDK w skryptach

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


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 pakietem Admin SDK

Pakiet Admin SDK jest przydatny do wykonywania operacji SQL Connect z uwzględnieniem tych kwestii.

Informacje o pakiecie SDK i dyrektywie operacji @auth(level: NO_ACCESS)

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

Jeśli oprócz operacji klienta organizujesz zapytania i mutacje administracyjne w plikach źródłowych .gql do importowania do skryptów administracyjnych, Firebase zaleca, aby operacje administracyjne oznaczyć bez poziomu dostępu autoryzacji lub bardziej wyraźnie ustawić je jako NO_ACCESS. W obu przypadkach uniemożliwi to wykonywanie takich operacji przez klientów lub w innych kontekstach bez uprawnień.

Używanie pakietu SDK z emulatorem SQL Connect

W środowiskach prototypowych i testowych może być przydatne przeprowadzanie inicjowania danych i innych operacji na danych produktów dostępnych lokalnie. 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 za pomocą przyjęcia tożsamości użytkownika).

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

export DATA_CONNECT_EMULATOR_HOST="127.0.0.1:9399"

Więcej informacji znajdziesz w tych materiałach:

Wykonywanie operacji administracyjnych

Pakiet Admin SDK jest przeznaczony do operacji z uprawnieniami na Twoich najważniejszych danych.

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

  • Wygenerowane pakiety Admin SDK, które są bezpiecznymi pod względem typów pakietami SDK wygenerowanymi na podstawie definicji gql w taki sam sposób, jak generujesz pakiety SDK klienta.
  • Ogólny interfejs do wykonywania dowolnych operacji GraphQL, w którym Twój 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 executeGraphql metod, udostępnia dedykowane metody operacji mutacji: insert, insertMany, upsert, i upsertMany.

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

Pakiety Admin SDK generujesz na podstawie definicji gql w taki sam sposób, jak generujesz 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 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ą jak najmniejszych uprawnień). Zamiast tego uruchom operację jako użytkownik, którego rolę odgrywasz (patrz następna sekcja), lub jako nieuwierzytelniony użytkownik, którego rolę odgrywasz. Nieuwierzytelnieni użytkownicy mogą uruchamiać tylko operacje oznaczone jako PUBLIC.

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

Odgrywanie roli innego użytkownika

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

Gdy odgrywasz rolę innego użytkownika, operacja zakończy się 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, konieczne jest, aby punkt końcowy wymagał uwierzytelnienia i aby przed użyciem tokena uwierzytelniania do odgrywania roli innego 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 } }
    );

    // ...
});

Identyfikator użytkownika, który nie pochodzi z weryfikowalnego źródła, należy określić tylko wtedy, gdy wykonujesz prawdziwe zadania administracyjne, takie jak migracja danych, w bezpiecznym środowisku niedostępnym publicznie:

// 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.

Zarządzanie danymi za pomocą metod executeGraphql

Jeśli musisz wykonać jednorazowe operacje, dla których nie zdefiniowano gql mutacji ani zapytań, możesz użyć metody executeGraphql lub metody tylko do odczytu executeGraphqlRead.

Odgrywanie roli nieuwierzytelnionego użytkownika

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

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

Odgrywanie roli innego użytkownika

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

Aby użyć tego interfejsu, zbierz informacje z dostosowanego tokena autoryzacji JWT, który jest zgodny z formatem tokena Authentication. 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, 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.

Wykonywanie operacji na danych zbiorczych

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 SQL 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 będzie powodować 1 podróż w obie strony do Cloud SQL, więc im więcej danych przetworzysz w ramach jednej operacji, tym większa będzie przepustowość.

Jednak im większa wielkość wsadu, tym dłuższa jest wygenerowana instrukcja SQL. Po osiągnięciu limitu długości instrukcji SQL PostgreSQL wystąpi błąd.

W praktyce eksperymentuj, aby znaleźć odpowiednią wielkość wsadu dla swojego obciążenia.

Co dalej?