获取我们在 Firebase 峰会上发布的所有信息,了解 Firebase 可如何帮助您加快应用开发速度并满怀信心地运行应用。了解详情

Twórz niestandardowe tokeny

Firebase zapewnia pełną kontrolę nad uwierzytelnianiem, umożliwiając uwierzytelnianie użytkowników lub urządzeń przy użyciu bezpiecznych tokenów internetowych JSON (JWT). Generujesz te tokeny na swoim serwerze, przekazujesz je z powrotem do urządzenia klienckiego, a następnie używasz ich do uwierzytelniania za pomocą metody signInWithCustomToken() .

Aby to osiągnąć, musisz utworzyć punkt końcowy serwera, który akceptuje poświadczenia logowania — takie jak nazwa użytkownika i hasło — i, jeśli poświadczenia są prawidłowe, zwraca niestandardowy token JWT. Niestandardowy token JWT zwrócony z serwera może być następnie używany przez urządzenie klienckie do uwierzytelniania w Firebase ( iOS+ , Android , web ). Po uwierzytelnieniu ta tożsamość będzie używana podczas uzyskiwania dostępu do innych usług Firebase, takich jak baza danych czasu rzeczywistego Firebase i Cloud Storage. Ponadto zawartość tokena JWT będzie dostępna w obiekcie auth w regułach bazy danych czasu rzeczywistego oraz w obiekcie request.auth w regułach zabezpieczeń Cloud Storage .

Możesz utworzyć token niestandardowy za pomocą pakietu Firebase Admin SDK lub użyć biblioteki JWT innej firmy, jeśli Twój serwer jest napisany w języku, którego Firebase nie obsługuje natywnie.

Zanim zaczniesz

Tokeny niestandardowe to podpisane tokeny JWT, w których klucz prywatny używany do podpisywania należy do konta usługi Google. Istnieje kilka sposobów określenia konta usługi Google, które ma być używane przez pakiet Firebase Admin SDK do podpisywania tokenów niestandardowych:

  • Korzystanie z pliku JSON konta usługi — tej metody można używać w dowolnym środowisku, ale wymaga spakowania pliku JSON konta usługi wraz z kodem. Należy zachować szczególną ostrożność, aby plik JSON konta usługi nie był udostępniany stronom zewnętrznym.
  • Pozwalanie pakietowi Admin SDK na wykrycie konta usługi – tej metody można używać w środowiskach zarządzanych przez Google, takich jak Google Cloud Functions i App Engine. Może być konieczne skonfigurowanie dodatkowych uprawnień za pośrednictwem Google Cloud Console.
  • Korzystanie z identyfikatora konta usługi – w przypadku użycia w środowisku zarządzanym przez Google ta metoda podpisuje tokeny przy użyciu klucza określonego konta usługi. Jednak korzysta ze zdalnej usługi internetowej i może być konieczne skonfigurowanie dodatkowych uprawnień dla tego konta usługi za pomocą Google Cloud Console.

Korzystanie z pliku JSON konta usługi

Pliki JSON konta usługi zawierają wszystkie informacje odpowiadające kontom usługi (w tym klucz prywatny RSA). Można je pobrać z konsoli Firebase. Postępuj zgodnie z instrukcjami konfiguracji pakietu Admin SDK, aby uzyskać więcej informacji na temat inicjowania pakietu Admin SDK za pomocą pliku JSON konta usługi.

Ta metoda inicjowania jest odpowiednia dla wielu wdrożeń pakietu Admin SDK. Umożliwia także zestawowi Admin SDK tworzenie i podpisywanie niestandardowych tokenów lokalnie, bez wykonywania żadnych zdalnych wywołań interfejsu API. Główną wadą tego podejścia jest to, że wymaga spakowania pliku JSON konta usługi wraz z kodem. Należy również pamiętać, że klucz prywatny w pliku JSON konta usługi to poufne informacje i należy zachować szczególną ostrożność, aby zachować jego poufność. W szczególności powstrzymaj się od dodawania plików JSON konta usługi do publicznej kontroli wersji.

Zezwalanie pakietowi Admin SDK na wykrywanie konta usługi

Jeśli Twój kod został wdrożony w środowisku zarządzanym przez Google, pakiet Admin SDK może spróbować automatycznie wykryć sposób podpisywania tokenów niestandardowych:

  • Jeśli Twój kod jest wdrożony w standardowym środowisku App Engine dla języka Java, Python lub Go, pakiet Admin SDK może używać usługi App Identity obecnej w tym środowisku do podpisywania tokenów niestandardowych. Usługa App Identity podpisuje dane przy użyciu konta usługi udostępnionego dla Twojej aplikacji przez Google App Engine.

  • Jeśli Twój kod został wdrożony w innym zarządzanym środowisku (np. Google Cloud Functions, Google Compute Engine), pakiet Firebase Admin SDK może automatycznie wykryć ciąg znaków identyfikatora konta usługi z lokalnego serwera metadanych . Odnaleziony identyfikator konta usługi jest następnie używany w połączeniu z usługą IAM do zdalnego podpisywania tokenów.

Aby skorzystać z tych metod podpisywania, zainicjuj pakiet SDK przy użyciu domyślnych poświadczeń aplikacji Google i nie podawaj ciągu identyfikatora konta usługi:

Node.js

initializeApp();

Jawa

FirebaseApp.initializeApp();

Pyton

default_app = firebase_admin.initialize_app()

Iść

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

C#

FirebaseApp.Create();

Aby przetestować ten sam kod lokalnie, pobierz plik JSON konta usługi i ustaw zmienną środowiskową GOOGLE_APPLICATION_CREDENTIALS tak, aby wskazywała na niego.

Jeśli pakiet Firebase Admin SDK musi wykryć ciąg znaków identyfikatora konta usługi, robi to, gdy kod tworzy niestandardowy token po raz pierwszy. Wynik jest buforowany i ponownie używany w kolejnych operacjach podpisywania tokena. Automatycznie wykryty identyfikator konta usługi jest zwykle jednym z domyślnych kont usługi udostępnianych przez Google Cloud:

Podobnie jak w przypadku jawnie określonych identyfikatorów kont usługi, automatycznie wykryte identyfikatory kont usług muszą mieć uprawnienie iam.serviceAccounts.signBlob , aby tworzenie tokenu niestandardowego mogło działać. Być może trzeba będzie użyć sekcji uprawnień i administratora w Google Cloud Console, aby przyznać domyślnym kontom usługi niezbędne uprawnienia. Więcej informacji znajdziesz w sekcji rozwiązywania problemów poniżej.

Korzystanie z identyfikatora konta usługi

Aby zachować spójność między różnymi częściami aplikacji, możesz określić identyfikator konta usługi, którego klucze będą używane do podpisywania tokenów w środowisku zarządzanym przez Google. Dzięki temu zasady uprawnień mogą być prostsze i bezpieczniejsze, a także uniknąć konieczności umieszczania w kodzie pliku JSON konta usługi.

Identyfikator konta usługi można znaleźć w Google Cloud Console lub w polu client_email pobranego pliku JSON konta usługi. Identyfikatory kont usługi to adresy e-mail w następującym formacie: <client-id>@<project-id>.iam.gserviceaccount.com . W unikalny sposób identyfikują konta usług w projektach Firebase i Google Cloud.

Aby utworzyć tokeny niestandardowe przy użyciu oddzielnego identyfikatora konta usługi, zainicjuj pakiet SDK, jak pokazano poniżej:

Node.js

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

Jawa

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

Pyton

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

Iść

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

Identyfikatory kont usługi nie są informacjami poufnymi, dlatego ich ujawnienie jest nieistotne. Aby jednak podpisać tokeny niestandardowe za pomocą określonego konta usługi, pakiet Firebase Admin SDK musi wywołać usługę zdalną. Ponadto musisz również upewnić się, że konto usługi, którego Admin SDK używa do wykonania tego wywołania — zwykle {project-name}@appspot.gserviceaccount.com — ma uprawnienie iam.serviceAccounts.signBlob . Więcej informacji znajdziesz w sekcji rozwiązywania problemów poniżej.

Twórz tokeny niestandardowe za pomocą pakietu Firebase Admin SDK

Pakiet Firebase Admin SDK ma wbudowaną metodę tworzenia tokenów niestandardowych. Jako minimum musisz podać uid , który może być dowolnym ciągiem, ale powinien jednoznacznie identyfikować użytkownika lub urządzenie, które uwierzytelniasz. Te tokeny wygasają po godzinie.

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

Jawa

String uid = "some-uid";

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

Pyton

uid = 'some-uid'

custom_token = auth.create_custom_token(uid)

Iść

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

Możesz również opcjonalnie określić dodatkowe oświadczenia, które zostaną uwzględnione w tokenie niestandardowym. Na przykład poniżej dodano pole premiumAccount do niestandardowego tokena, który będzie dostępny w obiektach auth / request.auth w Twoich regułach bezpieczeństwa:

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

Jawa

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

Pyton

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

custom_token = auth.create_custom_token(uid, additional_claims)

Iść

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

Zarezerwowane niestandardowe nazwy tokenów

Zaloguj się za pomocą niestandardowych tokenów na klientach

Po utworzeniu tokenu niestandardowego należy go wysłać do aplikacji klienckiej. Aplikacja kliencka uwierzytelnia się za pomocą tokena niestandardowego, wywołując signInWithCustomToken() :

iOS+

Cel C
[[FIRAuth auth] signInWithCustomToken:customToken
                           completion:^(FIRAuthDataResult * _Nullable authResult,
                                        NSError * _Nullable error) {
  // ...
}];
Szybki
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);
                }
            }
        });

Jedność

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

Web version 8

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

Web version 9

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

Jeśli uwierzytelnianie się powiedzie, użytkownik zostanie teraz zalogowany do aplikacji klienckiej przy użyciu konta określonego przez uid użytkownika zawarty w tokenie niestandardowym. Jeśli to konto wcześniej nie istniało, zostanie utworzony rekord dla tego użytkownika.

W taki sam sposób, jak w przypadku innych metod logowania (takich jak signInWithEmailAndPassword() i signInWithCredential() ), obiekt auth w regułach bazy danych czasu rzeczywistego i obiekt request.auth w regułach bezpieczeństwa Cloud Storage zostaną wypełnione uid użytkownika . W takim przypadku uid użytkownika będzie ten, który określiłeś podczas generowania tokenu niestandardowego.

Zasady bazy danych

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

Zasady przechowywania

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

Jeśli token niestandardowy zawiera dodatkowe oświadczenia, można odwoływać się do nich poza auth.token (Firebase Realtime Database) lub request.auth.token (Cloud Storage) w regułach:

Zasady bazy danych

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

Zasady przechowywania

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

Twórz niestandardowe tokeny za pomocą zewnętrznej biblioteki JWT

Jeśli Twój backend jest w języku, który nie ma oficjalnego pakietu SDK Firebase Admin, nadal możesz ręcznie tworzyć tokeny niestandardowe. Najpierw znajdź bibliotekę JWT innej firmy dla swojego języka. Następnie użyj tej biblioteki JWT, aby wygenerować token JWT, który zawiera następujące oświadczenia:

Roszczenia dotyczące tokenów niestandardowych
alg Algorytm "RS256"
iss Emitent Adres e-mail konta usługi Twojego projektu
sub Temat Adres e-mail konta usługi Twojego projektu
aud Publiczność "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit"
iat Wydane w czasie Aktualny czas w sekundach od epoki UNIX
exp Data ważności Czas w sekundach od epoki UNIX, w którym token wygasa. Może to być maksymalnie 3600 sekund później niż iat .
Uwaga: kontroluje to tylko czas wygaśnięcia tokenu niestandardowego . Ale po zalogowaniu użytkownika za pomocą signInWithCustomToken() pozostanie on zalogowany na urządzeniu do momentu unieważnienia sesji lub wylogowania użytkownika.
uid Unikalny identyfikator zalogowanego użytkownika musi być ciągiem o długości od 1 do 36 znaków
claims (opcjonalnie) Opcjonalne niestandardowe oświadczenia do uwzględnienia w zmiennych auth / request.auth reguł bezpieczeństwa

Oto kilka przykładowych implementacji tworzenia tokenów niestandardowych w różnych językach, których nie obsługuje pakiet Firebase Admin SDK:

PHP

Za pomocą 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

Używając 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

Po utworzeniu tokenu niestandardowego wyślij go do aplikacji klienckiej, aby użyć go do uwierzytelnienia w Firebase. Zobacz przykłady kodu powyżej, aby dowiedzieć się, jak to zrobić.

Rozwiązywanie problemów

W tej sekcji opisano niektóre typowe problemy, które programiści mogą napotkać podczas tworzenia tokenów niestandardowych oraz sposoby ich rozwiązywania.

Interfejs IAM API nie jest włączony

Jeśli określasz identyfikator konta usługi do podpisywania tokenów, może pojawić się błąd podobny do następującego:

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.

Pakiet Firebase Admin SDK używa interfejsu IAM API do podpisywania tokenów. Ten błąd oznacza, że ​​interfejs IAM API nie jest obecnie włączony w Twoim projekcie Firebase. Otwórz link w komunikacie o błędzie w przeglądarce internetowej i kliknij przycisk „Włącz API”, aby włączyć go dla swojego projektu.

Konto usługi nie ma wymaganych uprawnień

Jeśli konto usługi, na którym działa pakiet Firebase Admin SDK, nie ma uprawnienia iam.serviceAccounts.signBlob , może pojawić się komunikat o błędzie podobny do następującego:

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

Najłatwiejszym sposobem rozwiązania tego problemu jest przyznanie roli „Twórca tokenów konta usługi” danemu kontu usługi, zwykle {project-name}@appspot.gserviceaccount.com :

  1. Otwórz stronę uprawnień i administratora w Google Cloud Console.
  2. Wybierz swój projekt i kliknij „Kontynuuj”.
  3. Kliknij ikonę edycji odpowiadającą kontu usługi, które chcesz zaktualizować.
  4. Kliknij „Dodaj kolejną rolę”.
  5. Wpisz „Twórca tokenów konta usługi” w filtrze wyszukiwania i wybierz go z wyników.
  6. Kliknij „Zapisz”, aby potwierdzić przyznanie roli.

Więcej informacji na temat tego procesu znajdziesz w dokumentacji uprawnień lub dowiedz się, jak aktualizować role za pomocą narzędzi wiersza poleceń gcloud.

Nie udało się określić konta usługi

Jeśli pojawi się komunikat o błędzie podobny do poniższego, oznacza to, że pakiet Firebase Admin SDK nie został prawidłowo zainicjowany.

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

Jeśli korzystasz z pakietu SDK do automatycznego wykrywania identyfikatora konta usługi, upewnij się, że kod został wdrożony w zarządzanym środowisku Google z serwerem metadanych. W przeciwnym razie pamiętaj o określeniu pliku JSON konta usługi lub identyfikatora konta usługi podczas inicjowania zestawu SDK.