Mit Firebase haben Sie die vollständige Kontrolle über die Authentifizierung, indem Sie Benutzer oder Geräte mithilfe sicherer JSON-Web-Tokens (JWTs) authentifizieren können. Sie generieren diese Token auf Ihrem Server, geben sie an ein signInWithCustomToken()
und verwenden sie dann zur Authentifizierung über die signInWithCustomToken()
-Methode.
Um dies zu erreichen, müssen Sie einen Serverendpunkt erstellen, der Anmeldeinformationen akzeptiert, z. B. einen Benutzernamen und ein Kennwort. Wenn die Anmeldeinformationen gültig sind, wird ein benutzerdefiniertes JWT zurückgegeben. 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-Echtzeitdatenbank und den Cloud-Speicher verwendet. Darüber hinaus ist der Inhalt des JWT im auth
Objekt in Ihren Echtzeitdatenbankregeln und im request.auth
Objekt in Ihren Cloud Storage-Sicherheitsregeln request.auth
.
Sie können ein benutzerdefiniertes Token mit dem Firebase Admin SDK 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 verschiedene Möglichkeiten, das Google-Dienstkonto anzugeben, das vom Firebase Admin SDK zum Signieren benutzerdefinierter Token verwendet werden soll:
- Verwenden einer JSON-Datei für ein Dienstkonto - Diese Methode kann in jeder Umgebung verwendet werden, erfordert jedoch, dass Sie eine JSON-Datei für ein Dienstkonto zusammen mit Ihrem Code verpacken. Es muss besonders darauf geachtet werden, dass die JSON-Datei des Dienstkontos keinen externen Parteien zugänglich gemacht wird.
- Ermöglichen, 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.
- Verwenden einer Dienstkonto-ID - Bei Verwendung in einer von Google verwalteten Umgebung signiert diese Methode Token mit dem Schlüssel des angegebenen Dienstkontos. Es wird jedoch ein Remote-Webdienst verwendet, und Sie müssen möglicherweise zusätzliche Berechtigungen für dieses Dienstkonto über die Google Cloud Console konfigurieren.
Verwenden einer JSON-Datei für ein Dienstkonto
JSON-Dateien für Dienstkonten enthalten alle Informationen, die Dienstkonten entsprechen (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 das Dienstkonto zu erhalten.
Diese Initialisierungsmethode eignet sich für eine Vielzahl von Admin SDK-Bereitstellungen. Außerdem kann das Admin SDK benutzerdefinierte Token lokal erstellen und signieren, ohne Remote-API-Aufrufe durchführen zu müssen. Der Hauptnachteil dieses Ansatzes besteht darin, dass Sie eine JSON-Datei für das Dienstkonto zusammen mit Ihrem Code verpacken müssen. Beachten Sie auch, dass der private Schlüssel in einer JSON-Datei des Dienstkontos vertrauliche Informationen sind und dass besondere Sorgfalt darauf verwendet werden muss, diese vertraulich zu behandeln. Vermeiden Sie insbesondere das Hinzufügen von JSON-Dateien für Dienstkonten zur öffentlichen Versionskontrolle.
Lassen Sie das Admin SDK ein Dienstkonto erkennen
Wenn Ihr Code in einer von Google verwalteten Umgebung bereitgestellt wird, kann das Admin-SDK versuchen, ein Mittel zum Signieren benutzerdefinierter Token automatisch zu ermitteln:
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 zum Signieren benutzerdefinierter Token verwenden. 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 bereitgestellt wird (z. B. Google Cloud-Funktionen, Google Compute Engine), kann das Firebase Admin SDK eine Dienstkonto-ID-Zeichenfolge vom lokalen Metadatenserver automatisch erkennen. Die ID des erkannten Dienstkontos 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 von Google Application und geben Sie keine ID-Zeichenfolge für das Dienstkonto an:
Node.js
admin.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 JSON-Datei für das GOOGLE_APPLICATION_CREDENTIALS
herunter und setzen Sie die Umgebungsvariable GOOGLE_APPLICATION_CREDENTIALS
so, dass sie darauf GOOGLE_APPLICATION_CREDENTIALS
.
Wenn das Firebase Admin SDK eine Dienstkonto-ID-Zeichenfolge ermitteln 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 Standarddienstkonten, die von der Google Cloud bereitgestellt werden:
Genau wie bei explizit angegebenen Dienstkonto-IDs müssen automatisch iam.serviceAccounts.signBlob
Dienstkonto-IDs über die iam.serviceAccounts.signBlob
verfügen, damit die iam.serviceAccounts.signBlob
funktioniert. Möglicherweise müssen Sie den Abschnitt IAM und Admin der Google Cloud Console verwenden, um den Standarddienstkonten die erforderlichen Berechtigungen zu erteilen. Weitere Informationen finden Sie im Abschnitt zur Fehlerbehebung.
Verwenden einer Dienstkonto-ID
Um die Konsistenz zwischen verschiedenen Teilen Ihrer Anwendung zu gewährleisten, können Sie eine Dienstkonto-ID angeben, deren Schlüssel zum Signieren von Token verwendet werden, wenn diese in einer von Google verwalteten Umgebung ausgeführt werden. Dies kann IAM-Richtlinien einfacher und sicherer machen und vermeiden, dass die JSON-Datei des Dienstkontos in Ihren Code aufgenommen werden muss.
Die Dienstkonto-ID finden Sie in der Google Cloud Console oder im Feld client_email
einer heruntergeladenen JSON-Datei für das client_email
. <client-id>@<project-id>.iam.gserviceaccount.com
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.
Initialisieren Sie das SDK wie folgt, um benutzerdefinierte Token mit einer separaten Dienstkonto-ID zu erstellen:
Node.js
admin.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, weshalb ihre Offenlegung keine Rolle spielt. Um benutzerdefinierte Token mit dem angegebenen Dienstkonto zu signieren, muss das Firebase Admin SDK jedoch einen Remotedienst aufrufen. Darüber hinaus müssen Sie auch sicherstellen, dass das Dienstkonto das Admin SDK diesen Aufruf -Normalerweise machen wird mit {project-name}@appspot.gserviceaccount.com
- hat die iam.serviceAccounts.signBlob
Erlaubnis . Weitere Informationen finden Sie 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
, bei der es sich um eine beliebige Zeichenfolge uid
, die jedoch den Benutzer oder das Gerät, das Sie authentifizieren, eindeutig identifizieren soll. Diese Token verfallen nach einer Stunde.
Node.js
const uid = 'some-uid';
admin
.auth()
.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 aufgenommen werden sollen. Im Folgenden wurde premiumAccount
Feld " premiumAccount
ein benutzerdefiniertes Token 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,
};
admin
.auth()
.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
Melden Sie sich mit benutzerdefinierten Token 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, indem sie 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 mit dem Konto, das durch die im benutzerdefinierten Token enthaltene uid
angegeben wird, bei Ihrer Client-App uid
. Wenn dieses Konto zuvor nicht vorhanden war, wird ein Datensatz für diesen Benutzer erstellt.
Auf die gleiche Weise wie bei anderen signInWithEmailAndPassword()
(wie signInWithEmailAndPassword()
und signInWithCredential()
) werden das auth
Objekt in Ihren Echtzeitdatenbankregeln und das request.auth
Objekt in Ihren Cloud Storage-Sicherheitsregeln mit der Benutzer- uid
. 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 Sie in Ihren Regeln auf das Objekt auth.token
(Firebase Realtime Database) oder request.auth.token
(Cloud Storage) request.auth.token
:
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 mithilfe einer JWT-Bibliothek eines Drittanbieters
Wenn Ihr Backend in einer Sprache ohne offizielles Firebase Admin SDK vorliegt, können Sie dennoch manuell benutzerdefinierte Token erstellen. Suchen Sie zunächst eine JWT-Bibliothek eines Drittanbieters für Ihre Sprache. Verwenden Sie dann diese JWT-Bibliothek, um eine JWT zu prägen, die die folgenden Ansprüche enthält:
Benutzerdefinierte Token-Ansprüche | ||
---|---|---|
alg | Algorithmus | "RS256" |
iss | Aussteller | E-Mail-Adresse des Dienstkontos Ihres Projekts |
sub | Gegenstand | E-Mail-Adresse des Dienstkontos Ihres Projekts |
aud | Publikum | "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit" |
iat | Ausgestellt zum Zeitpunkt | 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. Es kann maximal 3600 Sekunden später als das iat .Hinweis: Dies steuert nur die Zeit, zu der das benutzerdefinierte Token selbst abläuft. Sobald Sie einen Benutzer mit signInWithCustomToken() , bleibt er am Gerät angemeldet, bis seine Sitzung ungültig wird oder der Benutzer sich signInWithCustomToken() . |
uid | Die eindeutige Kennung des angemeldeten Benutzers muss eine Zeichenfolge mit einer Länge zwischen 1 und 36 Zeichen sein | |
claims (optional) | Optionale benutzerdefinierte Ansprüche, die in die Variablen auth / request.auth der Sicherheitsregeln request.auth werden sollen |
Im Folgenden finden Sie einige Beispielimplementierungen zum Erstellen benutzerdefinierter Token in verschiedenen Sprachen, die vom Firebase Admin SDK nicht unterstützt werden:
PHP
Verwenden 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
Mit 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 sich bei Firebase zu authentifizieren. Informationen dazu finden Sie in den obigen Codebeispielen.
Fehlerbehebung
In diesem Abschnitt werden einige häufig auftretende Probleme beschrieben, auf die Entwickler beim Erstellen benutzerdefinierter Token stoßen können, und wie diese behoben werden können.
IAM-API nicht aktiviert
Wenn Sie eine Dienstkonto-ID zum Signieren von Token angeben, wird möglicherweise ein Fehler angezeigt, der dem folgenden ähnelt:
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 zeigt an, 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.
Für das Dienstkonto sind keine Berechtigungen erforderlich
Wenn das Dienstkonto, auf dem das Firebase Admin SDK ausgeführt wird, nicht über die iam.serviceAccounts.signBlob
, 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}.
Der einfachste Weg, dies zu beheben, besteht darin, dem betreffenden {project-name}@appspot.gserviceaccount.com
IAM-Rolle "Service Account Token Creator" {project-name}@appspot.gserviceaccount.com
, normalerweise {project-name}@appspot.gserviceaccount.com
:
- Öffnen Sie die IAM- und Administrationsseite in der Google Cloud Console.
- 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 "Service Account Token Creator" in den Suchfilter ein und wählen Sie ihn aus den Ergebnissen aus.
- Klicken Sie auf "Speichern", um die Rollengewährung zu bestätigen.
Weitere Informationen zu diesem Prozess finden Sie in der IAM-Dokumentation. Außerdem erfahren Sie, wie Sie Rollen mithilfe der Befehlszeilentools von gcloud aktualisieren.
Dienstkonto konnte nicht ermittelt werden
Wenn eine Fehlermeldung ähnlich der folgenden angezeigt wird, 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 beim automatischen Erkennen einer Dienstkonto-ID auf das SDK verlassen, stellen Sie sicher, dass der Code in einer verwalteten Google-Umgebung mit einem Metadatenserver bereitgestellt wird. Andernfalls müssen Sie bei der SDK-Initialisierung die JSON-Datei des Dienstkontos oder die Dienstkonto-ID angeben.