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). Wygenerować te znaki na serwerze, przekazać je z powrotem do urządzenia klienckiego, a następnie wykorzystać je do uwierzytelniania za pośrednictwem signInWithCustomToken() metody.

Aby to osiągnąć, należy 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. Zwyczaj JWT zwracane z serwera mogą być następnie wykorzystane przez urządzenie do uwierzytelniania klienta z Firebase ( iOS , Android , WWW ). 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ść JWT będzie dostępny w auth obiektu w swoim regulaminie Realtime baz danych i request.auth obiektu w swoim bagażu zasad bezpieczeństwa w chmurze .

Możesz utworzyć niestandardowy token 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 - Ta metoda może być stosowana w każdym środowisku, ale wymaga, aby spakować plik 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.
  • Pozwalając Admin SDK odkryć konto usługi - Ta metoda może być stosowana w środowiskach zarządzanych przez Google, takich jak Google Cloud and Functions App Engine. Może być konieczne skonfigurowanie dodatkowych uprawnień za pośrednictwem Google Cloud Console.
  • Korzystanie z identyfikatora konta usługi - Przy zastosowaniu w środowisku zarządzanym przez Google metoda ta podpisze tokeny za pomocą 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 Admin SDK skonfigurować instrukcji , aby uzyskać więcej informacji na temat sposobu inicjowania Admin SDK z 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żeli kod został umieszczony w standardowym środowisku App Engine dla Java, Python lub Go, Admin SDK mogą korzystać z usług App Identity obecne w tym środowisku do podpisania niestandardowych tokenów. Usługa App Identity podpisuje dane przy użyciu konta usługi udostępnionego dla Twojej aplikacji przez Google App Engine.

  • Jeśli kod jest wdrożony w jakimś innym środowisku zarządzanym (np funkcji Google Cloud, Google Compute Engine), to Firebase Admin SDK może automatycznie odkryć ciąg 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 danych logowania aplikacji Google i nie podawaj ciągu identyfikatora konta usługi:

Node.js

admin.initializeApp();

Jawa

FirebaseApp.initializeApp();

Pyton

default_app = firebase_admin.initialize_app()

Udać się

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

DO#

FirebaseApp.Create();

Aby przetestować ten sam kod lokalnie, należy pobrać plik JSON konta usługi i ustawić GOOGLE_APPLICATION_CREDENTIALS zmienną środowiskową pkt do 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 tokenu. Automatycznie wykryty identyfikator konta usługi jest zwykle jednym z domyślnych kont usługi udostępnianych przez Google Cloud:

Podobnie jak w przypadku wyraźnie określonych identyfikatorów konta usługi, identyfikatory konta usługi auto-discoverd musi mieć iam.serviceAccounts.signBlob zgody na tworzenie niestandardowych tokena do pracy. Być może trzeba będzie użyć IAM i Administracja sekcja konsoli Google Cloud udzielenia usługa domyślna stanowi 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 konsoli Google Cloud , czy w client_email dziedzinie pliku JSON konto pobrane usług. Identyfikatory kont usług są adresy e-mail, które mają format następujące: <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

admin.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)

Udać się

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

DO#

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 przy użyciu określonego konta usługi, pakiet Firebase Admin SDK musi wywołać usługę zdalną. Ponadto, należy również upewnić się, że usługa uwagę Admin SDK wykorzystuje do tego połączenia -usually {project-name}@appspot.gserviceaccount.com - ma iam.serviceAccounts.signBlob zgodę . Więcej informacji znajdziesz w sekcji rozwiązywania problemów poniżej.

Tworzenie tokenów niestandardowych za pomocą pakietu Firebase Admin SDK

Pakiet Firebase Admin SDK ma wbudowaną metodę tworzenia tokenów niestandardowych. Na minimum, trzeba zapewnić uid , który może być dowolny ciąg, ale powinien jednoznacznie identyfikować użytkownika lub urządzenie, które są autentyczną. Te tokeny wygasają po godzinie.

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

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)

Udać się

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)

DO#

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 mają być uwzględnione w tokenie niestandardowym. Na przykład, poniżej, premiumAccount pole zostało dodane do niestandardowego tokena, który będzie dostępny w auth / request.auth obiektów w swoich zasad bezpieczeństwa:

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

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)

Udać się

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)

DO#

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

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

Po utworzeniu tokenu niestandardowego należy go wysłać do aplikacji klienckiej. W app uwierzytelnia klienta ze zwyczajem Reklamowe 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);

Sieć

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

Jeśli autoryzacja się powiedzie, twój użytkownik będzie zalogowany w aplikacji klienckiej do swojego konta z określonego przez uid zawarte w niestandardowym tokena. 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() ) auth obiekt w swoim regulaminie Realtime baz danych i request.auth przedmiot w swoich zasad bezpieczeństwa Cloud Storage zostanie wypełnione użytkownika uid . W tym przypadku, uid będzie tym, który został podany podczas generowania niestandardowej token.

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 niestandardowy znacznik zawiera dodatkowe roszczenia, mogą odwoływać się od auth.token (Firebase Realtime Database) lub request.auth.token (Cloud Storage) obiekt 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. Po pierwsze, znaleźć bibliotekę JWT innej firmy dla swojego języka. Następnie użyj tej biblioteki JWT, aby wybić 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 Przedmiot 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 on wynosić maksymalnie 3600 sekund później niż iat .
Uwaga: to tylko kontroluje czas, kiedy sam zwyczaj tokenu wygasa. Ale Po zalogowaniu użytkownika w użyciu signInWithCustomToken() , będą nadal podpisane w urządzeniu aż do ich sesji zostało unieważnione lub znaki spośród użytkowników.
uid Unikalny identyfikator zalogowanego użytkownika musi być ciągiem o długości od 1 do 36 znaków
claims (opcjonalnie) Opcjonalne niestandardowe roszczenia do włączenia do przepisów bezpieczeństwa auth / request.auth zmiennych

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

PHP

Korzystanie z 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

Korzystanie 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 deweloperzy 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.

Firebase Admin SDK wykorzystuje API IAM do tokenów migowych. Ten błąd wskazuje, ż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żeli konto serwisowanie Firebase Admin SDK działa jak nie mają iam.serviceAccounts.signBlob zgody, może pojawić się komunikat o błędzie podobny do poniższego:

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

Najprostszym sposobem rozwiązania tego jest przyznanie „Service Account Reklamowe Creator” rolę IAM na konto usługa, zwykle {project-name}@appspot.gserviceaccount.com :

  1. Otwórz IAM i Administracja w konsoli Google Cloud.
  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.

Odnoszą się do dokumentacji IAM więcej szczegółów na temat tego procesu, lub dowiedzieć się, jak to zrobić aktualizacji ról przy użyciu narzędzi wiersza polecenia 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.