Firebase Admin SDK to zestaw bibliotek serwera, który umożliwia interakcję z Firebase z uprzywilejowanych środowisk w celu wykonywania działań takich jak zapytania i mutacje w usłudze Firebase SQL Connect na potrzeby zbiorczego zarządzania danymi i innych operacji z podwyższonymi uprawnieniami i podstawionymi danymi logowania.
Admin SDK udostępnia interfejs API do wywoływania operacji zarówno w trybie odczytu i zapisu, jak i w trybie tylko do odczytu. Dzięki operacjom tylko do odczytu możesz bez obaw wdrażać funkcje administracyjne, które nie mogą modyfikować danych w bazach danych.
Konfiguracja pakietu Admin SDK
Aby zacząć korzystać z Firebase SQL 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 SQL 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 wykonywania operacji SQL Connect, biorąc pod uwagę te kwestie.
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ą dyrektyw @auth, w tym poziomu NO_ACCESS.
Jeśli oprócz operacji klienta organizujesz zapytania i mutacje administracyjne w plikach źródłowych .gql do zaimportowania do skryptów administracyjnych, Firebase zaleca oznaczenie operacji administracyjnych bez poziomu dostępu autoryzacji lub, bardziej precyzyjnie, ustawienie ich jako NO_ACCESS. W obu przypadkach uniemożliwia to wykonywanie takich operacji z klientów lub w innych kontekstach bez uprawnień.
Używanie pakietu SDK z emulatorem SQL Connect
W środowiskach prototypowych i testowych przydatne może być wykonywanie operacji na danych lokalnych, takich jak wypełnianie bazy danych. Admin SDK pozwala uprościć przepływy pracy, ponieważ może ignorować uwierzytelnianie i autoryzację w przypadku przepływów lokalnych. (Możesz też wyraźnie wyrazić zgodę na przestrzeganie konfiguracji uwierzytelniania i autoryzacji operacji z przyjęciem tożsamości użytkownika).
Pakiety SDK Firebase Admin 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"
Aby dowiedzieć się więcej, zobacz:
wykonywać operacje administracyjne,
Admin SDK jest przeznaczona do operacji uprzywilejowanych na danych o kluczowym znaczeniu.
Pakiet Admin SDK udostępnia 3 zestawy interfejsów API:
- Wygenerowane pakiety Admin SDK, które są pakietami SDK z zabezpieczeniami wpisywania wygenerowanymi na podstawie definicji
gqlw taki sam sposób, jak pakiety SDK klienta. - Ogólny interfejs do wykonywania dowolnych operacji GraphQL, w którym kod implementuje zapytania i mutacje oraz przekazuje je do metody odczytu i zapisu
executeGraphqllub metody tylko do odczytuexecuteGraphqlRead. - Specjalistyczny interfejs do operacji na danych zbiorczych, który zamiast ogólnych metod
executeGraphqludostępnia specjalne metody do operacji mutacji:insert,insertMany,upsertiupsertMany.
Zarządzanie danymi za pomocą wygenerowanych pakietów SDK
Pakiety Admin SDK generujesz z definicji gql w taki sam sposób, jak pakiety SDK klienta.
Wygenerowany pakiet Admin SDK zawiera interfejsy i funkcje, które odpowiadają definicjom gql i 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ę oprogramowania sprzęgającego:
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 baz danych.
Podczas wykonywania operacji publicznych za pomocą pakietu Admin SDK unikaj wykonywania ich z pełnymi uprawnieniami administratora (zgodnie z zasadą jak najmniejszych uprawnień). Zamiast tego należy wykonać 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ą wykonywać 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 określonych użytkowników, przekazując część lub całość tokena Firebase Authentication w opcji impersonate. Musisz co najmniej podać identyfikator użytkownika w oświadczeniu sub. (Jest to ta sama wartość co wartość serwera auth.uid, do której możesz się odwoływać w operacjach GraphQL SQL Connect).
Gdy podszywasz się pod użytkownika, operacja powiedzie się 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, ważne jest, aby punkt końcowy wymagał uwierzytelniania i aby przed użyciem tokena uwierzytelniania do podszywania się pod użytkownika zweryfikować jego integralność.
Gdy używasz wywoływalnej funkcji Cloud Functions, token uwierzytelniania jest automatycznie weryfikowany 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 interfejsu Admin SDK, aby zweryfikować i zdekodować token uwierzytelniania. Załóżmy na przykład, że Twój 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, co jest 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 wiarygodnego źródła, należy podawać tylko podczas wykonywania prawdziwych zadań administracyjnych, takich jak migracja danych, z bezpiecznego, niedostępnego publicznie środowiska:
// Never do this if end users can initiate execution of the code!
const favoriteSongs = await getMyFavoriteSongs(
undefined,
{ impersonate: { authClaims } }
);
Działanie z nieograniczonym dostępem
Jeśli wykonujesz operację, która wymaga uprawnień na poziomie administratora, pomiń parametr personifikacji 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 tylko do celów administracyjnych, zdefiniuj je za pomocą dyrektywy @auth(level: NO_ACCESS). Dzięki temu tylko osoby dzwoniące z uprawnieniami administratora mogą wykonywać te operacje.
Zarządzanie danymi za pomocą metod executeGraphql
Jeśli musisz wykonać jednorazowe operacje, dla których nie zdefiniowano mutacji ani zapytań gql, możesz użyć metody executeGraphql lub metody executeGraphqlRead tylko do odczytu.
wykonywać niestandardowe zagnieżdżone operacje relacyjne (jeden do wielu i jeden do jednego) za pomocą executeGraphql;
Podczas wywoływania operacji z pakietu Admin SDK w środowisku uprzywilejowanym nie musisz określać dyrektywy @allow w zmiennych w przypadku standardowych wstawień płaskich (niezagnieżdżonych), takich jak wstawianie pojedynczych rekordów filmów lub aktorów.
Jednak w przypadku zagnieżdżonych wstawień relacyjnych (takich jak wstawienie filmu wraz z jego pierwszymi recenzjami lub użytkownika i jego profilu) nadal musisz zadeklarować dyrektywę @allow w definicji zmiennej, aby statycznie zezwolić na zagnieżdżone pola relacyjne w skompilowanym schemacie zmiennej.
// Custom GraphQL mutation with nested relational insert (one-to-many)
const customMutation = `
mutation CustomBatchInsert(
$data: [Movie_Data!]!
@allow(fields: "title genre reviews_on_movie { rating reviewText }")
) {
movie_insertMany(data: $data)
}
`;
const variables = {
data: [
{
title: "Interstellar",
genre: "Sci-Fi",
reviews_on_movie: [
{
rating: 5,
reviewText: "Visually stunning and emotionally powerful.",
user: { id: "user-789" }
}
]
}
]
};
const response = await dataConnect.executeGraphql(customMutation, { variables });
// Custom GraphQL mutation with a one-to-one nested relational insert
const customMutationOneToOne = `
mutation CustomBatchInsertOneToOne(
$data: [User_Data!]!
@allow(fields: "name profile_on_user { bio }")
) {
user_insertMany(data: $data)
}
`;
const variablesOneToOne = {
data: [
{
name: "Alice",
profile_on_user: {
bio: "Avid moviegoer and critic."
}
}
]
};
const responseOneToOne = await dataConnect.executeGraphql(customMutationOneToOne, { variables: variablesOneToOne });
Podszywanie się pod nieuwierzytelnionego użytkownika
Podczas wykonywania operacji publicznych za pomocą pakietu Admin SDK unikaj wykonywania ich z pełnymi uprawnieniami administratora (zgodnie z zasadą jak najmniejszych uprawnień). Zamiast tego należy uruchomić operację jako użytkownik, którego tożsamość została przejęta (patrz następna sekcja), lub jako nieuwierzytelniony użytkownik, którego tożsamość została przejęta. Nieuwierzytelnieni użytkownicy mogą wykonywać 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);
podszywanie się pod użytkownika,
Są też przypadki użycia, w których chcesz, aby skrypty modyfikowały dane użytkownika na podstawie ograniczonych danych logowania w imieniu konkretnego użytkownika. Takie 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 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ń na poziomie administratora, pomiń parametr personifikacji 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 tylko do celów administracyjnych, zdefiniuj je za pomocą dyrektywy @auth(level: NO_ACCESS). Dzięki temu tylko osoby dzwoniące z uprawnieniami administratora mogą wykonywać te operacje.
wykonywać operacje zbiorczego wstawiania danych,
Firebase zaleca używanie Admin SDK do operacji na danych zbiorczych w produkcyjnych bazach danych.
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);
Zagnieżdżone operacje relacyjne (jeden do wielu i jeden do jednego)
Admin SDK obsługuje dane relacyjne w operacjach zbiorczych. Podobnie jak w przypadku mutacji niestandardowych, użyj tablicy obiektów w przypadku relacji jeden do wielu i pojedynczego obiektu w przypadku relacji jeden do jednego:
// Example of inserting a movie with nested reviews (one-to-many)
const moviesData = [
{
title: "Interstellar",
genre: "Sci-Fi",
reviews_on_movie: [
{
rating: 5,
reviewText: "Visually stunning and emotionally powerful.",
user: { id: "user-789" }
}
]
}
];
// Atomically insert movies and their reviews in a single database round-trip.
const response = await dc.insertMany("movie", moviesData);
// Example of inserting a user with a nested profile (one-to-one)
const usersData = [
{
name: "Alice",
profile_on_user: {
bio: "Avid moviegoer and critic."
}
}
];
// Atomically insert users and their profiles.
const userResponse = await dc.insertMany("user", usersData);
Uwagi dotyczące wydajności operacji zbiorczych
Każde żądanie do backendu będzie wymagało jednej operacji w obie strony do Cloud SQL, więc im więcej żądań zgrupujesz, tym większa będzie przepustowość.
Jednak im większy rozmiar 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 rozmiar wsadu dla swojego zbioru zadań.
Co dalej?
- Dowiedz się, jak wypełniać bazy danych danymi za pomocą Admin SDK.
- Zapoznaj się z interfejsem API dla Admin SDK.
- Używaj interfejsu wiersza poleceń Firebase i konsoli Google Cloud do wykonywania innych operacji zarządzania projektem, takich jak zarządzanie schematami i oprogramowaniem sprzęgającym oraz zarządzanie usługami i bazami danych.