Firebase Data Connect SDK Admin vous permettent d'appeler vos requêtes et mutations à partir d' environnements de confiance tels que Cloud Functions, des backends personnalisés ou votre propre poste de travail. De la même manière que vous générez des SDK pour vos applications clientes, vous pouvez générer un SDK Admin personnalisé en parallèle lorsque vous concevez les schémas, les requêtes et les mutations que vous déployez dans votre Data Connect service. Ensuite, vous intégrez des méthodes de ce SDK dans votre logique de backend ou vos scripts d'administration.
Comme nous l'avons mentionné ailleurs, il est important de noter que les requêtes Data Connect et mutations ne sont pas envoyées par les clients au moment de la requête. Au lieu de cela, une fois déployées, les opérations Data Connect sont stockées sur le serveur, comme Cloud Functions. Cela signifie que chaque fois que vous déployez des modifications dans vos requêtes et mutations, vous devez également régénérer les SDK Admin et redéployer tous les services qui en dépendent.
Avant de commencer
- Découvrez comment concevoir des schémas, des requêtes et des mutations Data Connect. Dans un workflow typique, vous les développerez en parallèle du code de votre application, y compris tous les services qui utilisent des SDK Admin.
Incluez le SDK Admin pour Node.js en tant que dépendance partout où vous prévoyez d'appeler les SDK Admin générés.
Générer des SDK Admin
Une fois que vous avez créé vos Data Connect schémas, requêtes et mutations, vous pouvez générer un SDK Admin correspondant :
Ouvrez ou créez un fichier
connector.yamlet ajoutez une définitionadminNodeSdk:connectorId: default generate: adminNodeSdk: outputDir: ../../dataconnect-generated/admin-generated package: "@dataconnect/admin-generated" packageJsonDir: ../..Le fichier
connector.yamlse trouve généralement dans le même répertoire que les fichiers GraphQL (.gql) qui contiennent vos définitions de requête et de mutation. Si vous avez déjà généré des SDK client, ce fichier a déjà été créé.Générez le SDK.
Si l'extension Data Connect VS Code est installée, elle maintiendra toujours les SDK générés à jour.
Sinon, utilisez la CLI Firebase :
firebase dataconnect:sdk:generateVous pouvez également régénérer automatiquement les SDK lorsque vous mettez à jour vos fichiers
gql:firebase dataconnect:sdk:generate --watch
Exécuter des opérations à partir d'un SDK Admin
Le SDK Admin généré contient des interfaces et des fonctions qui correspondent à vos définitions gql, que vous pouvez utiliser pour effectuer des opérations sur votre base de données. Supposons, par exemple, que vous ayez généré un SDK pour une base de données de chansons, 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 de confiance et disposent donc d'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 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.
Dans l'exemple ci-dessus, la requête getSongs est exécutée en tant qu'utilisateur non authentifié.
Emprunter l'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 minimum spécifier l'ID utilisateur de l'utilisateur dans la revendication sub. (Il s'agit de la même valeur que la
auth.uid valeur de serveur
à laquelle vous pouvez faire référence dans les opérations GraphQL Data Connect.)
Lorsque vous empruntez l'identité d'un utilisateur, l'opération ne réussit que si les données utilisateur que vous avez fournies réussissent 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 des fonctions Cloud appelables Cloud Functions, 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 Admin SDK du verifyIdToken pour valider et décoder
le jeton d'authentification. Supposons, par exemple, que votre point de terminaison soit implémenté en tant que
fonction HTTP simple et que vous ayez transmis le Firebase Authentication jeton
à 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 des tâches d'administration réelles, 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écuter avec un accès illimité
Si vous effectuez une opération qui nécessite des autorisations de niveau administrateur, omettez le paramètre d'emprunt d'identité de l'appel :
await upsertSong(adminDc, {
title: songTitle_one,
instrumentsUsed: [Instrument.VOCAL],
});
Une opération appelée de cette manière dispose d'un accès complet à la base de données. Si vous avez des requêtes ou des mutations destinées à être utilisées uniquement à des fins d'administration, vous devez les définir avec la directive @auth(level: NO_ACCESS). Cela garantit que seuls les appelants de niveau administrateur peuvent exécuter ces opérations.