Admin SDK mit Data Connect verwenden

Die Firebase Admin SDK ist eine Reihe von Serverbibliotheken, mit denen Sie in 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 Massendatenverwaltung und andere Vorgänge mit erhöhten Berechtigungen und imitierten Anmeldedaten auszuführen.

Die Admin SDK bietet eine API zum Aufrufen von Vorgängen im Lese-/Schreibmodus und im schreibgeschützten Modus. Mit den schreibgeschützten Vorgängen können Sie administrative Funktionen implementieren, die keine Daten in Ihren Datenbanken ändern können.

Admin SDK einrichten

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

Admin SDK in Ihren Skripts initialisieren

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


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

Admin SDK ist nützlich, um Data Connect-Vorgänge auszuführen. Dabei sind die folgenden Aspekte zu berücksichtigen.

SDK und @auth(level: NO_ACCESS)-Vorgangsanweisung verstehen

Da Admin SDK mit Berechtigungen arbeitet, können damit alle Ihre Abfragen und Mutationen unabhängig von den mit @auth-Anweisungen festgelegten Zugriffsebenen ausgeführt werden, einschließlich der Ebene NO_ACCESS.

Wenn Sie neben Ihren Clientvorgängen Ihre administrativen Abfragen und Mutationen in .gql-Quelldateien für den Import in administrative Skripts organisieren, empfiehlt Firebase, die administrativen Vorgänge ohne Autorisierungszugriffsebene zu kennzeichnen oder sie expliziter als NO_ACCESS festzulegen. In beiden Fällen 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 hilfreich sein, Daten-Seeding und andere Vorgänge für lokale Daten auszuführen. Mit Admin SDK können Sie Ihre Workflows vereinfachen, da die Authentifizierung und Autorisierung für lokale Abläufe ignoriert werden kann. Sie können auch explizit zustimmen, dass die Authentifizierungs- und Autorisierungskonfiguration Ihrer Vorgänge mit der Identitätsübernahme von Nutzern übereinstimmt.

Die Firebase Admin SDKs stellen automatisch eine Verbindung zum Data Connect-Emulator her, wenn die Umgebungsvariable DATA_CONNECT_EMULATOR_HOST festgelegt ist:

export DATA_CONNECT_EMULATOR_HOST="127.0.0.1:9399"

Weitere Informationen finden Sie unter:

Verwaltungsvorgänge ausführen

Die Admin SDK wird für privilegierte Vorgänge für Ihre wichtigen Daten bereitgestellt.

Das Admin SDK bietet drei Gruppen von APIs:

  • Generierte Admin-SDKs: Das sind typsichere SDKs, die aus Ihren gql-Definitionen generiert werden, genau wie Client-SDKs.
  • Eine allgemeine Schnittstelle zum Ausführen beliebiger GraphQL-Vorgänge, in der Ihr Code Abfragen und Mutationen implementiert und an die Lese-/Schreibmethode executeGraphql oder die schreibgeschützte Methode executeGraphqlRead übergibt.
  • Eine spezielle Schnittstelle für Bulk-Datenvorgänge, die anstelle generischer 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 in Ihrer Datenbank ausführen. Angenommen, Sie haben ein SDK für eine Datenbank mit Songs zusammen mit einer Anfrage 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 } }
);

So geben Sie eine Connector-Konfiguration an:

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

Identität eines nicht authentifizierten Nutzers annehmen

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 vermeiden, den Vorgang mit vollständigen Administratorberechtigungen auszuführen (Prinzip der geringsten Berechtigung). Stattdessen sollten Sie den Vorgang entweder als imitierten Nutzer (siehe nächster Abschnitt) oder als imitierten nicht authentifizierten Nutzer ausführen. Nicht authentifizierte Nutzer können nur Vorgänge ausführen, die mit PUBLIC gekennzeichnet sind.

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

Identitätsdiebstahl

Sie können auch Vorgänge im Namen bestimmter Nutzer ausführen, indem Sie einen Teil oder das gesamte Firebase Authentication-Token in der Option impersonate übergeben. Mindestens müssen Sie 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 über einen öffentlich zugänglichen Endpunkt aufrufen, ist es wichtig, dass für den Endpunkt eine Authentifizierung erforderlich ist und dass Sie die Integrität des Authentifizierungstokens validieren, bevor Sie es verwenden, um die Identität eines Nutzers anzunehmen.

Wenn Sie aufrufbare Cloud Functions verwenden, wird das Authentifizierungstoken automatisch überprüft. 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 } }
    );

    // ...
});

Andernfalls verwenden Sie die Methode verifyIdToken des Admin SDK, um das Authentifizierungstoken zu validieren und zu decodieren. Angenommen, Ihr Endpunkt ist als einfache HTTP-Funktion implementiert und Sie haben das Firebase Authentication-Token wie üblich mit dem 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 administrative Aufgaben wie die Datenmigration in 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 Direktive @auth(level: NO_ACCESS) definieren. So wird sichergestellt, dass nur Anrufer mit Administratorberechtigungen 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 Methode executeGraphql oder die schreibgeschützte Methode executeGraphqlRead verwenden.

Identität eines nicht authentifizierten Nutzers annehmen

Wenn Sie öffentliche Vorgänge mit dem Admin SDK ausführen, sollten Sie vermeiden, den Vorgang mit vollständigen Administratorberechtigungen auszuführen (Prinzip der geringsten Berechtigung). Stattdessen sollten Sie den Vorgang entweder als imitierten Nutzer (siehe nächster Abschnitt) oder als imitierten nicht authentifizierten Nutzer ausführen. Nicht authentifizierte Nutzer können nur Vorgänge ausführen, die mit 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);

Identitätsdiebstahl

Es gibt auch Anwendungsfälle, in denen Sie möchten, dass Ihre Skripts Nutzerdaten im Namen eines bestimmten Nutzers auf Grundlage eingeschränkter Anmeldedaten ändern. Dieser Ansatz entspricht dem Prinzip der geringsten Berechtigung.

Um diese Schnittstelle zu verwenden, müssen Sie Informationen aus einem benutzerdefinierten JWT-Authentifizierungstoken abrufen, das dem Tokenformat Authentication entspricht. Weitere Informationen finden Sie im Leitfaden 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 Direktive @auth(level: NO_ACCESS) definieren. So wird sichergestellt, dass nur Anrufer mit Administratorberechtigungen diese Vorgänge ausführen können.

Bulk-Datenvorgänge ausführen

Firebase empfiehlt die Verwendung von Admin SDK für Massendatenvorgänge in Produktionsdatenbanken.

Das SDK bietet die folgenden Methoden für die Arbeit mit Bulk-Daten. Aus den bereitgestellten Argumenten wird mit jeder Methode eine GraphQL-Mutation erstellt und ausgeführt.


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

Für jede Anfrage an das Backend ist ein Roundtrip zu Cloud SQL erforderlich. Je mehr Sie also in Batches zusammenfassen, desto höher ist der Durchsatz.

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

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

Nächste Schritte