Admin SDK mit Data Connect verwenden

Das Firebase Admin SDK ist eine Reihe von Serverbibliotheken, mit denen Sie aus privilegierten Umgebungen mit Firebase interagieren können, um Aktionen wie das Ausführen von Abfragen und Mutationen für einen Firebase Data Connect Dienst zur Bulk-Datenverwaltung und andere Vorgänge mit erhöhten Berechtigungen und imitierten Anmeldedaten auszuführen.

Das Admin SDK bietet eine API, mit der Sie Vorgänge im Lese-/Schreibmodus und im schreibgeschützten Modus aufrufen können. Mit den schreibgeschützten Vorgängen können Sie Verwaltungsfunktionen implementieren, die keine Daten in Ihren Datenbanken ändern.

Admin SDK einrichten

Wenn Sie das mit Firebase Data Connect auf Ihrem Server verwenden möchten, müssen Sie zuerst das Admin SDK für Node.js installieren und einrichten.

Admin SDK in Ihren Skripts initialisieren

Importieren Sie die Data Connect Erweiterungen und deklarieren Sie die Dienst-ID und den Standort Ihres Projekts, um das SDK zu initialisieren.


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'
});

Abfragen und Mutationen für die Verwendung mit dem Admin SDK entwerfen

Das Admin SDK ist nützlich, um Data Connect Vorgänge auszuführen. Dabei sind jedoch die folgenden Punkte zu beachten.

SDK und @auth(level: NO_ACCESS)-Vorgangsanweisung

Da das Admin SDK mit Berechtigungen arbeitet, kann es alle Ihre Abfragen und Mutationen unabhängig von den mit @auth Anweisungen festgelegten Zugriffsebenen ausführen, einschließlich der Ebene NO_ACCESS.

Wenn Sie neben Ihren Clientvorgängen auch Ihre Verwaltungsabfragen und -mutationen in .gql-Quelldateien organisieren, um sie in Verwaltungsskripts zu importieren, empfiehlt Firebase, die Verwaltungsvorgänge ohne Zugriffsebene für die Autorisierung zu kennzeichnen oder sie expliziter als NO_ACCESS festzulegen. So wird verhindert, dass solche Vorgänge von Clients oder in anderen nicht privilegierten Kontexten ausgeführt werden.

SDK mit dem Data Connect Emulator verwenden

In Prototyp- und Testumgebungen kann es nützlich sein, Daten-Seeding und andere Vorgänge für lokale Daten auszuführen. Mit dem Admin SDK können Sie Ihre Arbeitsabläufe vereinfachen, da die Authentifizierung und Autorisierung für lokale Abläufe ignoriert werden können. Sie können auch explizit festlegen, dass die Authentifizierungs- und Autorisierungskonfiguration Ihrer Vorgänge mit dem Wechsel der Nutzeridentität eingehalten werden soll.

Das Firebase Admin SDK stellt automatisch eine Verbindung zum Data Connect Emulator her, wenn die DATA_CONNECT_EMULATOR_HOST Umgebungsvariable festgelegt ist:

export DATA_CONNECT_EMULATOR_HOST="127.0.0.1:9399"

Weitere Informationen finden Sie unter:

Admin-Vorgänge ausführen

Das Admin SDK wird für privilegierte Vorgänge für Ihre kritischen Daten bereitgestellt.

Das Admin SDK bietet drei Arten von APIs:

  • Generierte Admin SDKs: Das sind typsichere SDKs, die aus Ihren gql-Definitionen generiert werden, so wie Sie auch Client SDKs generieren.
  • Eine allgemeine Schnittstelle zum Ausführen beliebiger GraphQL-Vorgänge, in der Ihr Code Abfragen und Mutationen implementiert und sie an die Lese-/Schreibmethode executeGraphql oder die schreibgeschützte executeGraphqlRead Methode übergibt.
  • Eine spezielle Schnittstelle für Bulk-Datenvorgänge, die anstelle der generischen executeGraphql Methoden spezielle Methoden für Mutationsvorgänge bereitstellt: insert, insertMany, upsert, und upsertMany.

Daten mit generierten SDKs verwalten

Sie generieren Admin SDKs aus Ihren gql Definitionen auf dieselbe Weise wie Client SDKs.

Das generierte Admin SDK enthält Schnittstellen und Funktionen, die Ihren gql-Definitionen entsprechen. Damit können Sie Vorgänge für Ihre Datenbank ausführen. Angenommen, Sie haben ein SDK für eine Datenbank mit Songs zusammen mit einer Abfrage getSongs generiert:

import { initializeApp } from "firebase-admin/app";
import { getSongs } from "@dataconnect/admin-generated";

const adminApp = initializeApp();

const songs = await getSongs(
  { limit: 4 },
  { impersonate: { unauthenticated: true } }
);

Alternativ können Sie eine Connector-Konfiguration angeben:

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

Imitation eines nicht authentifizierten Nutzers

Admin SDKs sind für die Ausführung in vertrauenswürdigen Umgebungen vorgesehen und haben daher uneingeschränkten Zugriff auf Ihre Datenbanken.

Wenn Sie öffentliche Vorgänge mit dem Admin SDK ausführen, sollten Sie den Vorgang nicht mit vollständigen Administratorberechtigungen ausführen (Prinzip der geringsten Berechtigung). Stattdessen sollten Sie den Vorgang entweder als imitierter Nutzer (siehe nächster Abschnitt) oder als imitierter nicht authentifizierter Nutzer ausführen. Nicht authentifizierte Nutzer können nur Vorgänge ausführen, die als PUBLIC gekennzeichnet sind.

Im obigen Beispiel wird die Abfrage getSongs als nicht authentifizierter Nutzer ausgeführt.

Imitation eines Nutzers

Sie können auch Vorgänge im Namen bestimmter Nutzer ausführen, indem Sie einen Teil oder das gesamte Firebase Authentication Token in der impersonate Option übergeben. Sie müssen mindestens die Nutzer-ID des Nutzers im Anspruch „sub“ angeben. Dieser Wert entspricht dem auth.uid Serverwert auf den Sie in Data Connect GraphQL-Vorgängen verweisen können.

Wenn Sie einen Nutzer imitieren, ist der Vorgang nur erfolgreich, wenn die von Ihnen angegebenen Nutzerdaten die in Ihrer GraphQL-Definition angegebenen Authentifizierungsprüfungen bestehen.

Wenn Sie das generierte SDK von einem öffentlich zugänglichen Endpunkt aufrufen, ist es wichtig, dass der Endpunkt eine Authentifizierung erfordert und dass Sie die Integrität des Authentifizierungstokens prüfen, bevor Sie es verwenden, um einen Nutzer zu imitieren.

Bei aufrufbaren Cloud Functions wird das Authentifizierungstoken automatisch überprüft und Sie können es wie im folgenden Beispiel verwenden:

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

    // ...
});

Verwenden Sie andernfalls die Admin SDK's verifyIdToken Methode, um das Authentifizierungstoken zu validieren und zu decodieren. Angenommen, Ihr Endpunkt ist als eine einfache HTTP-Funktion implementiert und Sie haben das Firebase Authentication Token wie üblich über den authorization Header an Ihren Endpunkt übergeben:

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

    // ...
});

Nur wenn Sie echte Verwaltungsaufgaben wie die Datenmigration aus einer sicheren, nicht öffentlich zugänglichen Umgebung ausführen, sollten Sie eine Nutzer-ID angeben, die nicht aus einer überprüfbaren Quelle stammt:

// Never do this if end users can initiate execution of the code!
const favoriteSongs = await getMyFavoriteSongs(
  undefined,
  { impersonate: { authClaims } }
);

Mit uneingeschränktem Zugriff ausführen

Wenn Sie einen Vorgang ausführen, für den Berechtigungen auf Administratorebene erforderlich sind, lassen Sie den Parameter „impersonate“ im Aufruf weg:

await upsertSong(adminDc, {
  title: songTitle_one,
  instrumentsUsed: [Instrument.VOCAL],
});

Ein so aufgerufener Vorgang hat vollständigen Zugriff auf die Datenbank. Wenn Sie Abfragen oder Mutationen haben, die nur für Verwaltungszwecke verwendet werden sollen, sollten Sie sie mit der Anweisung @auth(level: NO_ACCESS) definieren. So wird sichergestellt, dass nur Aufrufer auf Administratorebene diese Vorgänge ausführen können.

Daten mit executeGraphql-Methoden verwalten

Wenn Sie einmalige Vorgänge ausführen müssen, für die Sie keine gql Mutationen oder Abfragen definiert haben, können Sie die executeGraphql Methode oder die schreibgeschützte executeGraphqlRead Methode verwenden.

Imitation eines nicht authentifizierten Nutzers

Wenn Sie öffentliche Vorgänge mit dem Admin SDK ausführen, sollten Sie den Vorgang nicht mit vollständigen Administratorberechtigungen ausführen (Prinzip der geringsten Berechtigung). Stattdessen sollten Sie den Vorgang entweder als imitierter Nutzer (siehe den nächsten Abschnitt) oder als imitierter nicht authentifizierter Nutzer ausführen. Nicht authentifizierte Nutzer können nur Vorgänge ausführen, die als PUBLIC gekennzeichnet sind.

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

Imitation eines Nutzers

Es gibt auch Anwendungsfälle, in denen Ihre Skripts Nutzerdaten mit eingeschränkten Anmeldedaten im Namen eines bestimmten Nutzers ändern sollen. Dieser Ansatz entspricht dem Prinzip der geringsten Berechtigung.

Um diese Schnittstelle zu verwenden, rufen Sie Informationen aus einem benutzerdefinierten JWT-Authentifizierungstoken ab, das dem Authentication Tokenformat entspricht. Weitere Informationen finden Sie in der Anleitung zu benutzerdefinierten Tokens.

// 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" } } }

Administratoranmeldedaten verwenden

Wenn Sie einen Vorgang ausführen, für den Berechtigungen auf Administratorebene erforderlich sind, lassen Sie den Parameter „impersonate“ im Aufruf weg:

// 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" } } }

Ein so aufgerufener Vorgang hat vollständigen Zugriff auf die Datenbank. Wenn Sie Abfragen oder Mutationen haben, die nur für Verwaltungszwecke verwendet werden sollen, sollten Sie sie mit der Anweisung @auth(level: NO_ACCESS) definieren. So wird sichergestellt, dass nur Aufrufer auf Administratorebene diese Vorgänge ausführen können.

Bulk-Datenvorgänge ausführen

Firebase empfiehlt, das Admin SDK für Bulk-Datenvorgänge in Produktionsdatenbanken zu verwenden.

Das SDK bietet die folgenden Methoden für die Arbeit mit Bulk-Daten. Aus den angegebenen Argumenten erstellt und führt jede Methode eine GraphQL-Mutation aus.


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

Hinweise zur Leistung bei Bulk-Vorgängen

Jede Anfrage an das Backend verursacht einen Roundtrip zu Cloud SQL. Je mehr Sie also im Batch verarbeiten, desto höher ist der Durchsatz.

Je größer die Batchgröße ist, desto länger ist jedoch auch die generierte SQL-Anweisung. Wenn die Längenbegrenzung für PostgreSQL-SQL-Anweisungen erreicht ist, tritt ein Fehler auf.

In der Praxis sollten Sie experimentieren, um die geeignete Batchgröße für Ihre Arbeitslast zu finden.

Nächste Schritte