Erstellen Sie benutzerdefinierte Token

Firebase gibt Ihnen die vollständige Kontrolle über die Authentifizierung, indem Sie Benutzer oder Geräte mit sicheren JSON Web Tokens (JWTs) authentifizieren können. Sie generieren diese Token auf Ihrem Server, geben sie an ein Clientgerät zurück und verwenden sie dann zur Authentifizierung über die Methode signInWithCustomToken() .

Um dies zu erreichen, müssen Sie einen Serverendpunkt erstellen, der Anmeldeinformationen akzeptiert – z. B. einen Benutzernamen und ein Kennwort – und, wenn die Anmeldeinformationen gültig sind, ein benutzerdefiniertes JWT zurückgibt. Das von Ihrem Server zurückgegebene benutzerdefinierte JWT kann dann von einem Clientgerät zur Authentifizierung bei Firebase ( iOS+ , Android , Web ) verwendet werden. Nach der Authentifizierung wird diese Identität beim Zugriff auf andere Firebase-Dienste wie die Firebase Realtime Database und Cloud Storage verwendet. Darüber hinaus sind die Inhalte des JWT im Objekt auth in Ihren Echtzeitdatenbankregeln und im Objekt request.auth in Ihren Cloud Storage-Sicherheitsregeln verfügbar.

Sie können mit dem Firebase Admin SDK ein benutzerdefiniertes Token erstellen oder eine JWT-Bibliothek eines Drittanbieters verwenden, wenn Ihr Server in einer Sprache geschrieben ist, die Firebase nicht nativ unterstützt.

Bevor Sie beginnen

Benutzerdefinierte Token sind signierte JWTs, bei denen der zum Signieren verwendete private Schlüssel zu einem Google-Dienstkonto gehört. Es gibt mehrere Möglichkeiten, das Google-Dienstkonto anzugeben, das vom Firebase Admin SDK zum Signieren benutzerdefinierter Token verwendet werden soll:

  • Verwenden einer Dienstkonto-JSON-Datei : Diese Methode kann in jeder Umgebung verwendet werden, erfordert jedoch, dass Sie eine Dienstkonto-JSON-Datei zusammen mit Ihrem Code packen. Es muss besonders darauf geachtet werden, dass die JSON-Datei des Dienstkontos nicht für externe Parteien verfügbar ist.
  • Zulassen, dass das Admin SDK ein Dienstkonto erkennt – Diese Methode kann in von Google verwalteten Umgebungen wie Google Cloud Functions und App Engine verwendet werden. Möglicherweise müssen Sie einige zusätzliche Berechtigungen über die Google Cloud Console konfigurieren.
  • Verwendung einer Dienstkonto-ID – Bei Verwendung in einer von Google verwalteten Umgebung signiert diese Methode Token mit dem Schlüssel des angegebenen Dienstkontos. Es verwendet jedoch einen Remote-Webdienst, und Sie müssen möglicherweise zusätzliche Berechtigungen für dieses Dienstkonto über die Google Cloud Console konfigurieren.

Verwenden einer Dienstkonto-JSON-Datei

JSON-Dateien für Dienstkonten enthalten alle Informationen zu Dienstkonten (einschließlich des privaten RSA-Schlüssels). Sie können von der Firebase-Konsole heruntergeladen werden. Befolgen Sie die Anweisungen zum Einrichten des Admin SDK, um weitere Informationen zum Initialisieren des Admin SDK mit einer JSON-Datei für Dienstkonten zu erhalten.

Diese Initialisierungsmethode eignet sich für eine Vielzahl von Admin SDK-Bereitstellungen. Außerdem ermöglicht es dem Admin SDK, benutzerdefinierte Token lokal zu erstellen und zu signieren, ohne Remote-API-Aufrufe durchzuführen. Der Hauptnachteil dieses Ansatzes besteht darin, dass Sie eine Dienstkonto-JSON-Datei zusammen mit Ihrem Code packen müssen. Beachten Sie auch, dass es sich bei dem privaten Schlüssel in einer JSON-Datei eines Dienstkontos um vertrauliche Informationen handelt und besondere Sorgfalt darauf verwendet werden muss, sie vertraulich zu behandeln. Unterlassen Sie insbesondere das Hinzufügen von JSON-Dateien für Dienstkonten zur öffentlichen Versionskontrolle.

Zulassen, dass das Admin SDK ein Dienstkonto erkennt

Wenn Ihr Code in einer von Google verwalteten Umgebung bereitgestellt wird, kann das Admin SDK versuchen, automatisch eine Möglichkeit zum Signieren benutzerdefinierter Token zu finden:

  • Wenn Ihr Code in der App Engine-Standardumgebung für Java, Python oder Go bereitgestellt wird, kann das Admin SDK den in dieser Umgebung vorhandenen App Identity-Dienst verwenden, um benutzerdefinierte Token zu signieren. Der App Identity-Dienst signiert Daten mithilfe eines Dienstkontos, das von Google App Engine für Ihre App bereitgestellt wird.

  • Wenn Ihr Code in einer anderen verwalteten Umgebung (z. B. Google Cloud Functions, Google Compute Engine) bereitgestellt wird, kann das Firebase Admin SDK automatisch eine Dienstkonto-ID-Zeichenfolge vom lokalen Metadatenserver erkennen . Die erkannte Dienstkonto-ID wird dann in Verbindung mit dem IAM-Dienst verwendet, um Token remote zu signieren.

Um diese Signaturmethoden zu verwenden, initialisieren Sie das SDK mit den Standardanmeldeinformationen für Google-Anwendungen und geben Sie keine Dienstkonto-ID-Zeichenfolge an:

Node.js

initializeApp();

Java

FirebaseApp.initializeApp();

Python

default_app = firebase_admin.initialize_app()

gehen

app, err := firebase.NewApp(context.Background(), nil)
if err != nil {
	log.Fatalf("error initializing app: %v\n", err)
}

C#

FirebaseApp.Create();

Um denselben Code lokal zu testen, laden Sie eine Dienstkonto-JSON-Datei herunter und legen Sie die Umgebungsvariable GOOGLE_APPLICATION_CREDENTIALS so fest, dass sie darauf verweist.

Wenn das Firebase Admin SDK eine Dienstkonto-ID-Zeichenfolge erkennen muss, geschieht dies, wenn Ihr Code zum ersten Mal ein benutzerdefiniertes Token erstellt. Das Ergebnis wird zwischengespeichert und für nachfolgende Token-Signaturvorgänge wiederverwendet. Die automatisch erkannte Dienstkonto-ID ist normalerweise eines der von Google Cloud bereitgestellten Standarddienstkonten:

Genau wie bei explizit angegebenen Dienstkonto-IDs müssen automatisch erkannte Dienstkonto-IDs über die iam.serviceAccounts.signBlob verfügen, damit die benutzerdefinierte Tokenerstellung funktioniert. Möglicherweise müssen Sie den IAM- und Admin -Bereich der Google Cloud Console verwenden, um den Standarddienstkonten die erforderlichen Berechtigungen zu erteilen. Weitere Einzelheiten finden Sie unten im Abschnitt zur Fehlerbehebung.

Verwenden einer Dienstkonto-ID

Um die Konsistenz zwischen verschiedenen Teilen Ihrer Anwendung zu wahren, können Sie eine Dienstkonto-ID angeben, deren Schlüssel zum Signieren von Token verwendet werden, wenn sie in einer von Google verwalteten Umgebung ausgeführt werden. Dadurch können IAM-Richtlinien einfacher und sicherer werden und Sie müssen die JSON-Datei des Dienstkontos nicht in Ihren Code aufnehmen.

Die Dienstkonto-ID finden Sie in der Google Cloud Console oder im Feld client_email einer heruntergeladenen Dienstkonto-JSON-Datei. Dienstkonto-IDs sind E-Mail-Adressen im folgenden Format: <client-id>@<project-id>.iam.gserviceaccount.com . Sie identifizieren Dienstkonten in Firebase- und Google Cloud-Projekten eindeutig.

Um benutzerdefinierte Token mit einer separaten Dienstkonto-ID zu erstellen, initialisieren Sie das SDK wie unten gezeigt:

Node.js

initializeApp({
  serviceAccountId: 'my-client-id@my-project-id.iam.gserviceaccount.com',
});

Java

FirebaseOptions options = FirebaseOptions.builder()
    .setCredentials(GoogleCredentials.getApplicationDefault())
    .setServiceAccountId("my-client-id@my-project-id.iam.gserviceaccount.com")
    .build();
FirebaseApp.initializeApp(options);

Python

options = {
    'serviceAccountId': 'my-client-id@my-project-id.iam.gserviceaccount.com',
}
firebase_admin.initialize_app(options=options)

gehen

conf := &firebase.Config{
	ServiceAccountID: "my-client-id@my-project-id.iam.gserviceaccount.com",
}
app, err := firebase.NewApp(context.Background(), conf)
if err != nil {
	log.Fatalf("error initializing app: %v\n", err)
}

C#

FirebaseApp.Create(new AppOptions()
{
    Credential = GoogleCredential.GetApplicationDefault(),
    ServiceAccountId = "my-client-id@my-project-id.iam.gserviceaccount.com",
});

Dienstkonto-IDs sind keine vertraulichen Informationen und daher ist ihre Offenlegung belanglos. Um jedoch benutzerdefinierte Token mit dem angegebenen Dienstkonto zu signieren, muss das Firebase Admin SDK einen Remotedienst aufrufen. Darüber hinaus müssen Sie auch sicherstellen, dass das Dienstkonto, das das Admin SDK verwendet, um diesen Aufruf zu tätigen – normalerweise {project-name}@appspot.gserviceaccount.com – über die Berechtigung iam.serviceAccounts.signBlob verfügt. Weitere Einzelheiten finden Sie unten im Abschnitt zur Fehlerbehebung.

Erstellen Sie benutzerdefinierte Token mit dem Firebase Admin SDK

Das Firebase Admin SDK verfügt über eine integrierte Methode zum Erstellen benutzerdefinierter Token. Sie müssen mindestens eine uid , die eine beliebige Zeichenfolge sein kann, aber den Benutzer oder das Gerät, das Sie authentifizieren, eindeutig identifizieren sollte. Diese Token verfallen nach einer Stunde.

Node.js

const uid = 'some-uid';

getAuth()
  .createCustomToken(uid)
  .then((customToken) => {
    // Send token back to client
  })
  .catch((error) => {
    console.log('Error creating custom token:', error);
  });

Java

String uid = "some-uid";

String customToken = FirebaseAuth.getInstance().createCustomToken(uid);
// Send token back to client

Python

uid = 'some-uid'

custom_token = auth.create_custom_token(uid)

gehen

client, err := app.Auth(context.Background())
if err != nil {
	log.Fatalf("error getting Auth client: %v\n", err)
}

token, err := client.CustomToken(ctx, "some-uid")
if err != nil {
	log.Fatalf("error minting custom token: %v\n", err)
}

log.Printf("Got custom token: %v\n", token)

C#

var uid = "some-uid";

string customToken = await FirebaseAuth.DefaultInstance.CreateCustomTokenAsync(uid);
// Send token back to client

Optional können Sie auch zusätzliche Ansprüche angeben, die in das benutzerdefinierte Token eingeschlossen werden sollen. Unten wurde dem benutzerdefinierten Token beispielsweise ein premiumAccount -Feld hinzugefügt, das in den Objekten auth / request.auth in Ihren Sicherheitsregeln verfügbar sein wird:

Node.js

const userId = 'some-uid';
const additionalClaims = {
  premiumAccount: true,
};

getAuth()
  .createCustomToken(userId, additionalClaims)
  .then((customToken) => {
    // Send token back to client
  })
  .catch((error) => {
    console.log('Error creating custom token:', error);
  });

Java

String uid = "some-uid";
Map<String, Object> additionalClaims = new HashMap<String, Object>();
additionalClaims.put("premiumAccount", true);

String customToken = FirebaseAuth.getInstance()
    .createCustomToken(uid, additionalClaims);
// Send token back to client

Python

uid = 'some-uid'
additional_claims = {
    'premiumAccount': True
}

custom_token = auth.create_custom_token(uid, additional_claims)

gehen

client, err := app.Auth(context.Background())
if err != nil {
	log.Fatalf("error getting Auth client: %v\n", err)
}

claims := map[string]interface{}{
	"premiumAccount": true,
}

token, err := client.CustomTokenWithClaims(ctx, "some-uid", claims)
if err != nil {
	log.Fatalf("error minting custom token: %v\n", err)
}

log.Printf("Got custom token: %v\n", token)

C#

var uid = "some-uid";
var additionalClaims = new Dictionary<string, object>()
{
    { "premiumAccount", true },
};

string customToken = await FirebaseAuth.DefaultInstance
    .CreateCustomTokenAsync(uid, additionalClaims);
// Send token back to client

Reservierte benutzerdefinierte Tokennamen

Melden Sie sich mit benutzerdefinierten Tokens auf Clients an

Nachdem Sie ein benutzerdefiniertes Token erstellt haben, sollten Sie es an Ihre Client-App senden. Die Client-App authentifiziert sich mit dem benutzerdefinierten Token durch Aufrufen von signInWithCustomToken() :

iOS+

Ziel c
[[FIRAuth auth] signInWithCustomToken:customToken
                           completion:^(FIRAuthDataResult * _Nullable authResult,
                                        NSError * _Nullable error) {
  // ...
}];
Schnell
Auth.auth().signIn(withCustomToken: customToken ?? "") { user, error in
  // ...
}

Android

mAuth.signInWithCustomToken(mCustomToken)
        .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
            @Override
            public void onComplete(@NonNull Task<AuthResult> task) {
                if (task.isSuccessful()) {
                    // Sign in success, update UI with the signed-in user's information
                    Log.d(TAG, "signInWithCustomToken:success");
                    FirebaseUser user = mAuth.getCurrentUser();
                    updateUI(user);
                } else {
                    // If sign in fails, display a message to the user.
                    Log.w(TAG, "signInWithCustomToken:failure", task.getException());
                    Toast.makeText(CustomAuthActivity.this, "Authentication failed.",
                            Toast.LENGTH_SHORT).show();
                    updateUI(null);
                }
            }
        });

Einheit

auth.SignInWithCustomTokenAsync(custom_token).ContinueWith(task => {
  if (task.IsCanceled) {
    Debug.LogError("SignInWithCustomTokenAsync was canceled.");
    return;
  }
  if (task.IsFaulted) {
    Debug.LogError("SignInWithCustomTokenAsync encountered an error: " + task.Exception);
    return;
  }

  Firebase.Auth.FirebaseUser newUser = task.Result;
  Debug.LogFormat("User signed in successfully: {0} ({1})",
      newUser.DisplayName, newUser.UserId);
});

C++

firebase::Future<firebase::auth::User*> result =
    auth->SignInWithCustomToken(custom_token);

Netz

firebase.auth().signInWithCustomToken(token)
  .then((userCredential) => {
    // Signed in
    var user = userCredential.user;
    // ...
  })
  .catch((error) => {
    var errorCode = error.code;
    var errorMessage = error.message;
    // ...
  });

Wenn die Authentifizierung erfolgreich ist, wird Ihr Benutzer jetzt bei Ihrer Client-App mit dem Konto angemeldet, das durch die im benutzerdefinierten Token enthaltene uid angegeben wird. Wenn dieses Konto zuvor nicht existierte, wird ein Datensatz für diesen Benutzer erstellt.

Genau wie bei anderen Anmeldemethoden (wie signInWithEmailAndPassword() und signInWithCredential() ) werden das auth -Objekt in Ihren Echtzeit-Datenbankregeln und das request.auth Objekt in Ihren Cloud Storage-Sicherheitsregeln mit der uid des Benutzers ausgefüllt. In diesem Fall ist die uid diejenige, die Sie beim Generieren des benutzerdefinierten Tokens angegeben haben.

Datenbankregeln

{
  "rules": {
    "adminContent": {
      ".read": "auth.uid === 'some-uid'"
    }
  }
}

Speicherregeln

service firebase.storage {
  match /b/<your-firebase-storage-bucket>/o {
    match /adminContent/{filename} {
      allow read, write: if request.auth != null && request.auth.uid == "some-uid";
    }
  }
}

Wenn das benutzerdefinierte Token zusätzliche Ansprüche enthält, können diese in Ihren Regeln vom Objekt auth.token (Firebase Realtime Database) oder request.auth.token (Cloud Storage) referenziert werden:

Datenbankregeln

{
  "rules": {
    "premiumContent": {
      ".read": "auth.token.premiumAccount === true"
    }
  }
}

Speicherregeln

service firebase.storage {
  match /b/<your-firebase-storage-bucket>/o {
    match /premiumContent/{filename} {
      allow read, write: if request.auth.token.premiumAccount == true;
    }
  }
}

Erstellen Sie benutzerdefinierte Token mit einer JWT-Bibliothek eines Drittanbieters

Wenn Ihr Back-End in einer Sprache ist, die kein offizielles Firebase Admin SDK hat, können Sie trotzdem manuell benutzerdefinierte Token erstellen. Suchen Sie zunächst eine JWT-Bibliothek eines Drittanbieters für Ihre Sprache. Verwenden Sie dann diese JWT-Bibliothek, um ein JWT zu prägen, das die folgenden Ansprüche enthält:

Benutzerdefinierte Token-Ansprüche
alg Algorithmus "RS256"
iss Aussteller Die E-Mail-Adresse des Dienstkontos Ihres Projekts
sub Gegenstand Die E-Mail-Adresse des Dienstkontos Ihres Projekts
aud Publikum "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit"
iat Ausgestellt zur Zeit Die aktuelle Zeit in Sekunden seit der UNIX-Epoche
exp Ablaufzeit Die Zeit in Sekunden seit der UNIX-Epoche, zu der das Token abläuft. Er darf maximal 3600 Sekunden später als der iat sein.
Hinweis: Dies steuert nur die Zeit, zu der das benutzerdefinierte Token selbst abläuft. Aber sobald Sie einen Benutzer mit signInWithCustomToken() , bleibt er beim Gerät angemeldet, bis seine Sitzung ungültig wird oder der Benutzer sich abmeldet.
uid Die eindeutige Kennung des angemeldeten Benutzers muss eine Zeichenfolge mit einer Länge von 1 bis 36 Zeichen sein
claims (optional) Optionale benutzerdefinierte Ansprüche, die in die auth / request.auth Variablen der Sicherheitsregeln aufgenommen werden sollen

Hier sind einige Beispielimplementierungen zum Erstellen benutzerdefinierter Token in einer Vielzahl von Sprachen, die das Firebase Admin SDK nicht unterstützt:

PHP

Verwendung von php-jwt :

// Requires: composer require firebase/php-jwt
use Firebase\JWT\JWT;

// Get your service account's email address and private key from the JSON key file
$service_account_email = "abc-123@a-b-c-123.iam.gserviceaccount.com";
$private_key = "-----BEGIN PRIVATE KEY-----...";

function create_custom_token($uid, $is_premium_account) {
  global $service_account_email, $private_key;

  $now_seconds = time();
  $payload = array(
    "iss" => $service_account_email,
    "sub" => $service_account_email,
    "aud" => "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
    "iat" => $now_seconds,
    "exp" => $now_seconds+(60*60),  // Maximum expiration time is one hour
    "uid" => $uid,
    "claims" => array(
      "premium_account" => $is_premium_account
    )
  );
  return JWT::encode($payload, $private_key, "RS256");
}

Rubin

Verwendung von ruby-jwt :

require "jwt"

# Get your service account's email address and private key from the JSON key file
$service_account_email = "service-account@my-project-abc123.iam.gserviceaccount.com"
$private_key = OpenSSL::PKey::RSA.new "-----BEGIN PRIVATE KEY-----\n..."

def create_custom_token(uid, is_premium_account)
  now_seconds = Time.now.to_i
  payload = {:iss => $service_account_email,
             :sub => $service_account_email,
             :aud => "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
             :iat => now_seconds,
             :exp => now_seconds+(60*60), # Maximum expiration time is one hour
             :uid => uid,
             :claims => {:premium_account => is_premium_account}}
  JWT.encode payload, $private_key, "RS256"
end

Nachdem Sie das benutzerdefinierte Token erstellt haben, senden Sie es an Ihre Client-App, um es für die Authentifizierung bei Firebase zu verwenden. Sehen Sie sich die obigen Codebeispiele an, um zu erfahren, wie Sie dies tun.

Fehlerbehebung

In diesem Abschnitt werden einige allgemeine Probleme beschrieben, auf die Entwickler beim Erstellen benutzerdefinierter Token stoßen können, und wie sie gelöst werden können.

IAM-API nicht aktiviert

Wenn Sie eine Dienstkonto-ID zum Signieren von Token angeben, erhalten Sie möglicherweise eine Fehlermeldung ähnlich der folgenden:

Identity and Access Management (IAM) API has not been used in project
1234567890 before or it is disabled. Enable it by visiting
https://console.developers.google.com/apis/api/iam.googleapis.com/overview?project=1234567890
then retry. If you enabled this API recently, wait a few minutes for the action
to propagate to our systems and retry.

Das Firebase Admin SDK verwendet die IAM-API zum Signieren von Token. Dieser Fehler weist darauf hin, dass die IAM-API derzeit nicht für Ihr Firebase-Projekt aktiviert ist. Öffnen Sie den Link in der Fehlermeldung in einem Webbrowser und klicken Sie auf die Schaltfläche „API aktivieren“, um ihn für Ihr Projekt zu aktivieren.

Das Dienstkonto verfügt nicht über die erforderlichen Berechtigungen

Wenn das Dienstkonto, unter dem das Firebase Admin SDK ausgeführt wird, nicht über die iam.serviceAccounts.signBlob , erhalten Sie möglicherweise eine Fehlermeldung wie die folgende:

Permission iam.serviceAccounts.signBlob is required to perform this operation
on service account projects/-/serviceAccounts/{your-service-account-id}.

Der einfachste Weg, dies zu lösen, besteht darin, dem betreffenden Dienstkonto, normalerweise {project-name}@appspot.gserviceaccount.com , die IAM-Rolle „Service Account Token Creator“ zuzuweisen:

  1. Öffnen Sie die IAM- und Verwaltungsseite in der Google Cloud Console.
  2. Wählen Sie Ihr Projekt aus und klicken Sie auf „Weiter“.
  3. Klicken Sie auf das Bearbeitungssymbol des Dienstkontos, das Sie aktualisieren möchten.
  4. Klicken Sie auf „Weitere Rolle hinzufügen“.
  5. Geben Sie „Service Account Token Creator“ in den Suchfilter ein und wählen Sie es aus den Ergebnissen aus.
  6. Klicken Sie auf „Speichern“, um die Rollenzuweisung zu bestätigen.

Weitere Informationen zu diesem Vorgang finden Sie in der IAM-Dokumentation oder erfahren Sie, wie Sie Rollen mit den gcloud-Befehlszeilentools aktualisieren.

Dienstkonto konnte nicht ermittelt werden

Wenn Sie eine Fehlermeldung ähnlich der folgenden erhalten, wurde das Firebase Admin SDK nicht ordnungsgemäß initialisiert.

Failed to determine service account ID. Initialize the SDK with service account
credentials or specify a service account ID with iam.serviceAccounts.signBlob
permission.

Wenn Sie sich auf das SDK verlassen, um eine Dienstkonto-ID automatisch zu erkennen, stellen Sie sicher, dass der Code in einer verwalteten Google-Umgebung mit einem Metadatenserver bereitgestellt wird. Stellen Sie andernfalls sicher, dass Sie die JSON-Datei oder die Dienstkonto-ID des Dienstkontos bei der SDK-Initialisierung angeben.