Firebase Admin SDK est un ensemble de bibliothèques de serveur qui vous permet d'interagir avec Firebase à partir d'environnements privilégiés pour effectuer des actions telles que des requêtes et des mutations sur un service Firebase Data Connect pour la gestion des données groupées et d'autres opérations avec des droits d'accès élevés et des identifiants usurpés.
Admin SDK vous fournit une API pour appeler des opérations en mode lecture/écriture et en mode lecture seule. Les opérations en lecture seule vous permettent d'implémenter des fonctions administratives qui ne peuvent pas modifier les données de vos bases de données.
Configuration du SDK Admin
Pour commencer à utiliser Firebase Data Connect sur votre serveur, vous devez d'abord installer et configurer la Admin SDK pour Node.js.
Initialiser le SDK Admin dans vos scripts
Pour initialiser le SDK, importez les extensions Data Connect et déclarez l'ID et l'emplacement du service de votre projet.
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'
});
Concevoir des requêtes et des mutations à utiliser avec Admin SDK
Admin SDK est utile pour exécuter des opérations Data Connect, en tenant compte des considérations suivantes.
Comprendre le SDK et la directive d'opération @auth(level: NO_ACCESS)
Étant donné que Admin SDK fonctionne avec des droits d'accès, il peut exécuter n'importe laquelle de vos requêtes et mutations, quels que soient les niveaux d'accès définis à l'aide des directives @auth, y compris le niveau NO_ACCESS.
Si, en plus de vos opérations client, vous organisez vos requêtes et mutations administratives dans des fichiers sources .gql à importer dans des scripts administratifs, Firebase vous recommande de marquer les opérations administratives sans aucun niveau d'accès à l'autorisation, ou peut-être d'être plus explicite et de les définir sur NO_ACCESS. Dans les deux cas, cela empêche l'exécution de telles opérations à partir de clients ou dans d'autres contextes non privilégiés.
Utiliser le SDK avec l'émulateur Data Connect
Dans les environnements de prototypage et de test, il peut être utile d'effectuer l'amorçage des données et d'autres opérations sur les données locales. L'option Admin SDK vous permet de simplifier vos workflows, car elle peut ignorer l'authentification et l'autorisation pour les flux locaux. (Vous pouvez également choisir explicitement de respecter la configuration d'authentification et d'autorisation de vos opérations avec l'usurpation d'identité.)
Les SDK Admin Firebase se connectent automatiquement à l'émulateur Data Connect lorsque la variable d'environnement DATA_CONNECT_EMULATOR_HOST est définie :
export DATA_CONNECT_EMULATOR_HOST="127.0.0.1:9399"
Pour en savoir plus, consultez les pages suivantes :
- Le guide sur l'amorçage des données dans le développement local
- La documentation de l'émulateur Data Connect
Effectuer des opérations d'administration
Admin SDK est fourni pour les opérations privilégiées sur vos données critiques.
Le SDK Admin fournit trois ensembles d'API :
- SDK Admin générés, qui sont des SDK de type sécurisé générés à partir de vos définitions
gqlde la même manière que vous générez des SDK client. - Interface générale permettant d'exécuter des opérations GraphQL arbitraires, dans laquelle votre code implémente des requêtes et des mutations, et les transmet à la méthode
executeGraphqlen lecture/écriture ou à la méthodeexecuteGraphqlReaden lecture seule. - Interface spécialisée pour les opérations sur les données groupées, qui, au lieu des méthodes
executeGraphqlgénériques, expose des méthodes dédiées aux opérations de mutation :insert,insertMany,upsertetupsertMany.
Gérer les données avec les SDK générés
Vous pouvez générer des SDK Admin à partir de vos définitions gql de la même manière que vous générez des SDK client.
Le SDK Admin généré contient des interfaces et des fonctions qui correspondent à vos définitions gql. Vous pouvez les utiliser pour effectuer des opérations sur votre base de données. Par exemple, supposons que vous ayez généré un SDK pour une base de données de titres, ainsi qu'une requête, 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 } }
);
Vous pouvez également spécifier une configuration de connecteur :
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 } }
);
Emprunter l'identité d'un utilisateur non authentifié
Les SDK Admin sont conçus pour être exécutés à partir d'environnements fiables. Ils ont donc un accès illimité à vos bases de données.
Lorsque vous exécutez des opérations publiques avec le SDK Admin, vous devez éviter de les exécuter avec des droits d'administrateur complets (en suivant le principe du moindre privilège). Vous devez plutôt exécuter l'opération en tant qu'utilisateur usurpé (voir la section suivante) ou en tant qu'utilisateur non authentifié usurpé.
Les utilisateurs non authentifiés ne peuvent exécuter que les opérations marquées comme PUBLIC.
Dans l'exemple ci-dessus, la requête getSongs est exécutée en tant qu'utilisateur non authentifié.
Usurpation d'identité d'un utilisateur
Vous pouvez également effectuer des opérations au nom d'utilisateurs spécifiques en transmettant une partie ou la totalité d'un jeton Firebase Authentication dans l'option impersonate. Vous devez au moins spécifier l'ID utilisateur de l'utilisateur dans la revendication "sub". (Il s'agit de la même valeur que la valeur du serveur auth.uid que vous pouvez référencer dans les opérations GraphQL de Data Connect.)
Lorsque vous usurpez l'identité d'un utilisateur, l'opération ne réussit que si les données utilisateur que vous avez fournies passent les vérifications d'authentification spécifiées dans votre définition GraphQL.
Si vous appelez le SDK généré à partir d'un point de terminaison accessible au public, il est essentiel que le point de terminaison nécessite une authentification et que vous validiez l'intégrité du jeton d'authentification avant de l'utiliser pour emprunter l'identité d'un utilisateur.
Lorsque vous utilisez Cloud Functions appelable, le jeton d'authentification est automatiquement vérifié et vous pouvez l'utiliser comme dans l'exemple suivant :
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 } }
);
// ...
});
Sinon, utilisez la méthode verifyIdToken de Admin SDK pour valider et décoder le jeton d'authentification. Par exemple, supposons que votre point de terminaison soit implémenté en tant que fonction HTTP simple et que vous ayez transmis le jeton Firebase Authentication à votre point de terminaison à l'aide de l'en-tête authorization, comme c'est la norme :
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 } }
);
// ...
});
Vous ne devez spécifier un ID utilisateur qui ne provient pas d'une source vérifiable que lorsque vous effectuez de véritables tâches administratives, telles que la migration de données, à partir d'un environnement sécurisé et non accessible au public :
// Never do this if end users can initiate execution of the code!
const favoriteSongs = await getMyFavoriteSongs(
undefined,
{ impersonate: { authClaims } }
);
Exécution avec un accès non restreint
Si vous effectuez une opération qui nécessite des autorisations d'administrateur, omettez le paramètre "impersonate" de l'appel :
await upsertSong(adminDc, {
title: songTitle_one,
instrumentsUsed: [Instrument.VOCAL],
});
Une opération appelée de cette manière a un accès complet à la base de données. Si vous avez des requêtes ou des mutations destinées uniquement à des fins d'administration, vous devez les définir avec la directive @auth(level: NO_ACCESS). Cela permet de s'assurer que seuls les appelants de niveau administrateur peuvent exécuter ces opérations.
Gérer les données avec les méthodes executeGraphql
Si vous devez exécuter des opérations ponctuelles pour lesquelles vous n'avez pas défini de mutations ou de requêtes gql, vous pouvez utiliser la méthode executeGraphql ou la méthode executeGraphqlRead en lecture seule.
Emprunter l'identité d'un utilisateur non authentifié
Lorsque vous exécutez des opérations publiques avec le SDK Admin, vous devez éviter de les exécuter avec des droits d'administrateur complets (en suivant le principe du moindre privilège). À la place, vous devez exécuter l'opération en tant qu'utilisateur emprunté (voir la section suivante) ou en tant qu'utilisateur non authentifié emprunté. Les utilisateurs non authentifiés ne peuvent exécuter que les opérations marquées comme 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);
Usurpation d'identité d'un utilisateur
Dans certains cas d'utilisation, vous souhaitez que vos scripts modifient les données utilisateur en fonction d'identifiants limités, au nom d'un utilisateur spécifique. Cette approche respecte le principe du moindre privilège.
Pour utiliser cette interface, collectez des informations à partir d'un jeton d'authentification JWT personnalisé qui suit le format de jeton Authentication. Consultez également le guide sur les jetons personnalisés.
// 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" } } }
Utiliser des identifiants administrateur
Si vous effectuez une opération qui nécessite des autorisations d'administrateur, omettez le paramètre "impersonate" de l'appel :
// 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" } } }
Une opération appelée de cette manière a un accès complet à la base de données. Si vous avez des requêtes ou des mutations destinées uniquement à des fins d'administration, vous devez les définir avec la directive @auth(level: NO_ACCESS). Cela permet de s'assurer que seuls les appelants de niveau administrateur peuvent exécuter ces opérations.
Effectuer des opérations groupées sur les données
Firebase vous recommande d'utiliser Admin SDK pour les opérations sur les données groupées dans les bases de données de production.
Le SDK fournit les méthodes suivantes pour travailler avec des données groupées. À partir des arguments fournis, chaque méthode construit et exécute une mutation 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);
Remarques sur les performances pour les opérations groupées
Chaque requête envoyée au backend entraînera un aller-retour vers Cloud SQL. Par conséquent, plus vous regroupez les requêtes, plus le débit sera élevé.
Toutefois, plus la taille du lot est importante, plus l'instruction SQL générée est longue. Lorsque la limite de longueur des instructions SQL PostgreSQL est atteinte, une erreur se produit.
En pratique, faites des tests pour trouver la taille de lot appropriée à votre charge de travail.
Étape suivante
- Découvrez comment alimenter vos bases de données avec des données à l'aide de Admin SDK.
- Consultez l'API pour Admin SDK.
- Utilisez la CLI Firebase et la console Google Cloud pour d'autres opérations de gestion de projet, comme gérer les schémas et les connecteurs et gérer les services et les bases de données.