Firebase bietet Ihnen die vollständige Kontrolle über die Authentifizierung, da Sie Nutzer oder Geräte mit sicheren JSON-Webtokens (JWTs) authentifizieren können. Sie generieren diese Tokens auf Ihrem Server, übergeben sie an ein Clientgerät und verwenden sie dann zur Authentifizierung über die Methode signInWithCustomToken().
Dazu müssen Sie einen Serverendpunkt erstellen, der Anmeldedaten wie einen Nutzernamen und ein Passwort akzeptiert und bei gültigen Anmeldedaten ein benutzerdefiniertes JWT zurückgibt. Das von Ihrem Server zurückgegebene benutzerdefinierte JWT kann dann
von einem Clientgerät zur Authentifizierung bei Firebase verwendet werden
(iOS+, Android,
Web). Nach der Authentifizierung wird diese Identität für den Zugriff auf andere Firebase-Dienste wie die Firebase Realtime Database
und Cloud Storage verwendet. Außerdem sind die Inhalte des JWT
im Objekt auth in Ihren
Realtime Database Security Rules und im Objekt
request.auth in Ihren
Cloud Storage Security Rules verfügbar.
Sie können ein benutzerdefiniertes Token mit dem Firebase Admin SDK erstellen oder die JWT-Bibliothek eines Drittanbieters verwenden, wenn Ihr Server in einer Sprache geschrieben ist, die von Firebase nicht nativ unterstützt wird.
Hinweis
Benutzerdefinierte Tokens sind signierte JWTs, bei denen der für die Signierung 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 Tokens verwendet werden soll:
- JSON-Datei des Dienstkontos verwenden – Diese Methode kann in jeder Umgebung verwendet werden, erfordert jedoch, dass Sie eine JSON-Datei des Dienstkontos zusammen mit Ihrem Code verpacken. Sie müssen besonders darauf achten, dass die JSON-Datei des Dienstkontos nicht für externe Parteien zugänglich ist.
- Dienstkonto vom Admin SDK ermitteln lassen : 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 Konsole konfigurieren.
- Dienstkonto-ID verwenden: Wenn diese Methode in einer von Google verwalteten Umgebung verwendet wird, werden Tokens mit dem Schlüssel des angegebenen Dienstkontos signiert. Dabei wird jedoch ein Remote-Webdienst verwendet und Sie müssen möglicherweise zusätzliche Berechtigungen für dieses Dienstkonto über die Google Cloud Konsole konfigurieren.
JSON-Datei des Dienstkontos verwenden
JSON-Dateien von Dienstkonten enthalten alle Informationen zu Dienstkonten, einschließlich des privaten RSA-Schlüssels. Sie können in der Firebase Console heruntergeladen werden. Weitere Informationen zum Initialisieren des Admin SDK mit einer JSON-Datei des Dienstkontos finden Sie in der Einrichtungsanleitung für das Admin SDK.
Diese Initialisierungsmethode eignet sich für eine Vielzahl von Admin SDK-Bereitstellungen. Außerdem kann das Admin SDK damit benutzerdefinierte Tokens lokal erstellen und signieren, ohne Remote-API-Aufrufe auszuführen. Der Hauptnachteil dieses Ansatzes besteht darin, dass Sie eine JSON-Datei des Dienstkontos zusammen mit Ihrem Code verpacken müssen. Außerdem ist der private Schlüssel in einer JSON-Datei des Dienstkontos vertraulich und muss besonders geschützt werden. Fügen Sie JSON-Dateien von Dienstkonten insbesondere nicht der öffentlichen Versionsverwaltung hinzu.
Dienstkonto vom Admin SDK ermitteln lassen
Wenn Ihr Code in einer von Google verwalteten Umgebung bereitgestellt wird, kann das Admin SDK versuchen, automatisch eine Methode zum Signieren benutzerdefinierter Tokens zu ermitteln:
Wenn Ihr Code in der App Engine Standardumgebung für Java, Python oder Go bereitgestellt wird, kann das Admin SDK den App Identity-Dienst in dieser Umgebung zum Signieren benutzerdefinierter Tokens verwenden. Der App Identity-Dienst signiert Daten mit einem Dienstkonto, das von Google App Engine für Ihre App bereitgestellt wurde.
Wenn Ihr Code in einer anderen verwalteten Umgebung bereitgestellt wird (z.B. Google Cloud Functions, Google Compute Engine), kann das Firebase Admin SDK automatisch einen Dienstkonto-ID-String vom lokalen Metadatenserver ermitteln. Die ermittelte Dienstkonto-ID wird dann in Verbindung mit dem IAM-Dienst verwendet, um Tokens remote zu signieren.
Um diese Signierungsmethoden zu verwenden, initialisieren Sie das SDK mit den Standardanmeldedaten der Google-Anwendung und geben Sie keinen Dienstkonto-ID-String an:
Node.js
initializeApp();
Java
FirebaseApp.initializeApp();
Python
default_app = firebase_admin.initialize_app()
Go
app, err := firebase.NewApp(context.Background(), nil)
if err != nil {
log.Fatalf("error initializing app: %v\n", err)
}
C#
FirebaseApp.Create();
Wenn Sie denselben Code lokal testen möchten, laden Sie eine JSON-Datei des Dienstkontos herunter und legen Sie die Umgebungsvariable GOOGLE_APPLICATION_CREDENTIALS so fest, dass sie darauf verweist.
Wenn das Firebase Admin SDK einen Dienstkonto-ID-String ermitteln muss, geschieht dies, wenn Ihr Code zum ersten Mal ein benutzerdefiniertes Token erstellt. Das Ergebnis wird im Cache gespeichert und für nachfolgende Token-Signierungsvorgänge wiederverwendet. Die automatisch ermittelte Dienstkonto-ID ist in der Regel eine der Standarddienst konten, die von Google Cloud bereitgestellt werden:
Wie bei explizit angegebenen Dienstkonto-IDs müssen auch automatisch ermittelte Dienstkonto-IDs die Berechtigung iam.serviceAccounts.signBlob haben, damit die Erstellung benutzerdefinierter Tokens funktioniert. Möglicherweise müssen Sie im
Bereich „IAM und Verwaltung“ der Google Cloud Console den Standarddienstkonten die
erforderlichen Berechtigungen gewähren. Weitere Informationen finden Sie im Abschnitt zur Fehlerbehebung weiter unten.
Dienstkonto-ID verwenden
Um die Konsistenz zwischen verschiedenen Teilen Ihrer Anwendung zu gewährleisten, können Sie eine Dienstkonto-ID angeben, deren Schlüssel zum Signieren von Tokens verwendet werden, wenn die Anwendung in einer von Google verwalteten Umgebung ausgeführt wird. Dadurch können IAM-Richtlinien einfacher und sicherer werden und Sie müssen die JSON-Datei des Dienstkontos nicht in Ihren Code einfügen.
Die Dienstkonto-ID finden Sie in der
Google Cloud Konsole,
oder im client_email Feld einer heruntergeladenen JSON-Datei des Dienstkontos.
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.
Wenn Sie benutzerdefinierte Tokens mit einer separaten Dienstkonto-ID erstellen möchten, 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)
Go
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 unbedenklich. Um benutzerdefinierte Tokens mit dem angegebenen Dienstkonto zu signieren, muss das Firebase Admin SDK jedoch einen Remote-Dienst aufrufen.
Außerdem müssen Sie dafür sorgen, dass das Dienstkonto, das vom Admin SDK für diesen Aufruf verwendet wird – in der Regel {project-name}@appspot.gserviceaccount.com – die iam.serviceAccounts.signBlob
Berechtigung hat.
Weitere Informationen finden Sie im Abschnitt zur Fehlerbehebung weiter unten.
Benutzerdefinierte Tokens mit dem Firebase Admin SDK erstellen
Das Firebase Admin SDK verfügt über eine integrierte Methode zum Erstellen benutzerdefinierter Tokens. Sie müssen mindestens eine uid angeben. Das kann ein beliebiger String sein, der den Nutzer oder das Gerät, das Sie authentifizieren, eindeutig identifiziert. Diese Tokens laufen nach einer Stunde ab.
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)
Go
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 Anforderungen angeben, die in das benutzerdefinierte Token aufgenommen werden sollen. Im folgenden Beispiel wurde dem
benutzerdefinierten Token das Feld premiumAccount hinzugefügt, das in den Objekten auth / request.auth
in Ihren Sicherheitsregeln verfügbar ist:
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)
Go
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 Namen benutzerdefinierter Tokens
Mit benutzerdefinierten Tokens auf Clients anmelden
Nachdem Sie ein benutzerdefiniertes Token erstellt haben, sollten Sie es an Ihre Client-App senden. Die Client-App authentifiziert sich mit dem benutzerdefinierten Token, indem sie signInWithCustomToken() aufruft:
iOS+
Objective-C
[[FIRAuth auth] signInWithCustomToken:customToken
completion:^(FIRAuthDataResult * _Nullable authResult,
NSError * _Nullable error) {
// ...
}];
Swift
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.AuthResult result = task.Result;
Debug.LogFormat("User signed in successfully: {0} ({1})",
result.User.DisplayName, result.User.UserId);
});
C++
firebase::Future<firebase::auth::AuthResult> result =
auth->SignInWithCustomToken(custom_token);
Web
firebase.auth().signInWithCustomToken(token)
.then((userCredential) => {
// Signed in
var user = userCredential.user;
// ...
})
.catch((error) => {
var errorCode = error.code;
var errorMessage = error.message;
// ...
});
Web
import { getAuth, signInWithCustomToken } from "firebase/auth";
const auth = getAuth();
signInWithCustomToken(auth, token)
.then((userCredential) => {
// Signed in
const user = userCredential.user;
// ...
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
// ...
});
Wenn die Authentifizierung erfolgreich ist, ist Ihr Nutzer jetzt mit dem Konto in Ihrer Client-App angemeldet, das durch die in das benutzerdefinierte Token aufgenommene uid angegeben wird. Wenn dieses Konto noch nicht vorhanden war, wird ein Eintrag für diesen Nutzer erstellt.
Wie bei anderen Anmeldemethoden (z. B.
signInWithEmailAndPassword() und signInWithCredential()) wird das Objekt auth in Ihren Realtime Database Security Rules und das Objekt request.auth in Ihren Cloud Storage Security Rules mit der uid des Nutzers gefüllt. In diesem Fall ist die uid die, 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 Anforderungen enthält, können Sie in Ihren Regeln auf das Objekt
auth.token (Firebase Realtime Database) oder request.auth.token
(Cloud Storage) verweisen:
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;
}
}
}
Benutzerdefinierte Tokens mit der JWT-Bibliothek eines Drittanbieters erstellen
Wenn Ihr Back-End in einer Sprache geschrieben ist, für die es kein offizielles Firebase Admin SDK gibt, können Sie trotzdem benutzerdefinierte Tokens manuell erstellen. Suchen Sie zuerst, nach einer JWT-Bibliothek eines Drittanbieters für Ihre Sprache. Verwenden Sie dann diese JWT-Bibliothek, um ein JWT zu reduzieren, das die folgenden Anforderungen enthält:
| Benutzerdefinierte Token-Anforderungen | ||
|---|---|---|
alg |
Algorithmus | "RS256" |
iss |
Aussteller | Die E-Mail-Adresse des Dienstkontos Ihres Projekts |
sub |
Betreff | Die E-Mail-Adresse des Dienstkontos Ihres Projekts |
aud |
Zielgruppe | "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit" |
iat |
Ausstellungszeit | 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. Dies kann maximal 3.600 Sekunden später als iat sein.
Beachten Sie, dass damit nur der Zeitpunkt gesteuert wird, zu dem das benutzerdefinierte Token selbst abläuft. Wenn Sie jedoch einen Nutzer mit signInWithCustomToken() anmelden, bleiben er so lange auf dem
Gerät angemeldet, bis die Sitzung ungültig wird oder der Nutzer sich abmeldet.
|
uid |
Die eindeutige ID des angemeldeten Nutzers muss ein String mit einer Länge von
1 bis 128 Zeichen sein. Kürzere uids bieten eine bessere
Leistung.
|
|
claims (optional) |
Optionale benutzerdefinierte Anforderungen, die in die Variablen der Sicherheitsregeln auth /
request.auth aufgenommen werden sollen
|
|
Hier sind einige Beispielimplementierungen zum Erstellen benutzerdefinierter Tokens in verschiedenen Sprachen, die vom Firebase Admin SDK nicht unterstützt werden:
PHP
Mit 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");
}
Ruby
ruby-jwt verwenden:
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, damit sie sich bei Firebase authentifizieren kann. Wie das geht, sehen Sie in den obigen Codebeispielen.
Fehlerbehebung
In diesem Abschnitt werden einige häufige Probleme beschrieben, die bei der Erstellung benutzerdefinierter Tokens auftreten können, und wie Sie sie beheben.
IAM API nicht aktiviert
Wenn Sie eine Dienstkonto-ID zum Signieren von Tokens angeben, wird möglicherweise ein Fehler wie der folgende angezeigt:
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 Tokens. Dieser Fehler weist darauf hin, dass die IAM API derzeit für Ihr Firebase-Projekt nicht aktiviert ist. Öffnen Sie den Link in der Fehlermeldung in einem Webbrowser und klicken Sie auf die Schaltfläche „API aktivieren“, um sie für Ihr Projekt zu aktivieren.
Dienstkonto hat nicht die erforderlichen Berechtigungen
Wenn das Dienstkonto, unter dem das Firebase Admin SDK ausgeführt wird, nicht die Berechtigung iam.serviceAccounts.signBlob hat, wird möglicherweise eine Fehlermeldung wie die folgende angezeigt:
Permission iam.serviceAccounts.signBlob is required to perform this operation
on service account projects/-/serviceAccounts/{your-service-account-id}.
Um dieses Problem zu beheben, weisen Sie dem entsprechenden Dienstkonto die IAM-Rolle Ersteller von Dienstkonto-Tokens zu. Das verwendete Standarddienstkonto hängt von der Umgebung und der Cloud Functions-Version ab:
- Cloud Functions (1. Generation) : Verwendet das Standarddienstkonto von App Engine.
- Cloud Functions (2. Generation) : Verwendet das Standarddienstkonto von Compute Engine.
- Öffnen Sie in der Google Cloud Console die IAM und Verwaltung Seite.
- Wählen Sie Ihr Projekt aus und klicken Sie auf „Weiter“.
- Klicken Sie auf das Bearbeitungssymbol für das Dienstkonto, das Sie aktualisieren möchten.
- Klicken Sie auf „Weitere Rolle hinzufügen“.
- Geben Sie „Ersteller von Dienstkonto-Tokens“ in den Suchfilter ein und wählen Sie die Rolle in den Ergebnissen aus.
- Klicken Sie auf „Speichern“, um die Rollenzuweisung zu bestätigen.
Weitere Informationen zu diesem Vorgang finden Sie in der IAM-Dokumentation . Informationen zum Aktualisieren von Rollen mit den gcloud-Befehlszeilentools finden Sie hier.
Dienstkonto konnte nicht ermittelt werden
Wenn Sie eine Fehlermeldung wie die folgende 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 darauf verlassen, dass das SDK automatisch eine Dienstkonto-ID ermittelt, muss der Code in einer verwalteten Google-Umgebung mit einem Metadatenserver bereitgestellt werden. Andernfalls müssen Sie bei der SDK-Initialisierung eine JSON-Datei des Dienstkontos oder eine Dienstkonto-ID angeben.