Join us in person and online for Firebase Summit on October 18, 2022. Learn how Firebase can help you accelerate app development, release your app with confidence, and scale with ease. Register now

Crea token personalizzati

Mantieni tutto organizzato con le raccolte Salva e classifica i contenuti in base alle tue preferenze.

Firebase ti offre il controllo completo sull'autenticazione consentendoti di autenticare utenti o dispositivi utilizzando JSON Web Token (JWT) sicuri. Generi questi token sul tuo server, li restituisci a un dispositivo client e quindi li usi per autenticarti tramite il metodo signInWithCustomToken() .

Per ottenere ciò, è necessario creare un endpoint server che accetti le credenziali di accesso, ad esempio un nome utente e una password, e, se le credenziali sono valide, restituisca un JWT personalizzato. Il JWT personalizzato restituito dal tuo server può quindi essere utilizzato da un dispositivo client per autenticarsi con Firebase ( iOS+ , Android , web ). Una volta autenticata, questa identità verrà utilizzata per accedere ad altri servizi Firebase, come Firebase Realtime Database e Cloud Storage. Inoltre, il contenuto del JWT sarà disponibile nell'oggetto auth nelle Regole del database in tempo reale e nell'oggetto request.auth nelle Regole di sicurezza del cloud storage .

Puoi creare un token personalizzato con Firebase Admin SDK oppure puoi utilizzare una libreria JWT di terze parti se il tuo server è scritto in una lingua che Firebase non supporta in modo nativo.

Prima di iniziare

I token personalizzati sono JWT firmati in cui la chiave privata utilizzata per la firma appartiene a un account di servizio Google. Esistono diversi modi per specificare l'account di servizio Google che deve essere utilizzato da Firebase Admin SDK per la firma di token personalizzati:

  • Utilizzo di un file JSON dell'account di servizio : questo metodo può essere utilizzato in qualsiasi ambiente, ma richiede di creare un pacchetto di un file JSON dell'account di servizio insieme al codice. È necessario prestare particolare attenzione per garantire che il file JSON dell'account di servizio non sia esposto a parti esterne.
  • Consentire all'SDK di amministrazione di rilevare un account di servizio : questo metodo può essere utilizzato in ambienti gestiti da Google come Google Cloud Functions e App Engine. Potrebbe essere necessario configurare alcune autorizzazioni aggiuntive tramite Google Cloud Console.
  • Utilizzo di un ID account di servizio : se utilizzato in un ambiente gestito da Google, questo metodo firmerà i token utilizzando la chiave dell'account di servizio specificato. Tuttavia, utilizza un servizio Web remoto e potrebbe essere necessario configurare autorizzazioni aggiuntive per questo account di servizio tramite Google Cloud Console.

Utilizzo di un file JSON dell'account di servizio

I file JSON dell'account di servizio contengono tutte le informazioni corrispondenti agli account di servizio (inclusa la chiave privata RSA). Possono essere scaricati dalla console Firebase. Segui le istruzioni di configurazione dell'SDK di amministrazione per ulteriori informazioni su come inizializzare l'SDK di amministrazione con un file JSON dell'account di servizio.

Questo metodo di inizializzazione è adatto per un'ampia gamma di distribuzioni di Admin SDK. Consente inoltre all'Admin SDK di creare e firmare token personalizzati in locale, senza effettuare chiamate API remote. Lo svantaggio principale di questo approccio è che richiede di creare un pacchetto di un file JSON dell'account di servizio insieme al codice. Tieni inoltre presente che la chiave privata in un file JSON dell'account di servizio è un'informazione riservata e che è necessario prestare particolare attenzione per mantenerla riservata. In particolare, astenersi dall'aggiungere file JSON dell'account di servizio al controllo della versione pubblica.

Consentire all'SDK di amministrazione di rilevare un account di servizio

Se il tuo codice viene distribuito in un ambiente gestito da Google, Admin SDK può tentare di scoprire automaticamente un mezzo per firmare token personalizzati:

  • Se il codice viene distribuito nell'ambiente standard di App Engine per Java, Python o Go, l'SDK di amministrazione può utilizzare il servizio App Identity presente in tale ambiente per firmare token personalizzati. Il servizio App Identity firma i dati utilizzando un account di servizio fornito per la tua app da Google App Engine.

  • Se il codice viene distribuito in un altro ambiente gestito (ad es. Google Cloud Functions, Google Compute Engine), Firebase Admin SDK può rilevare automaticamente una stringa ID account di servizio dal server di metadati locale . L'ID account del servizio rilevato viene quindi utilizzato insieme al servizio IAM per firmare i token in remoto.

Per utilizzare questi metodi di firma, inizializza l'SDK con le credenziali predefinite dell'applicazione Google e non specificare una stringa ID account di servizio:

Node.js

initializeApp();

Giava

FirebaseApp.initializeApp();

Pitone

default_app = firebase_admin.initialize_app()

andare

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

C#

FirebaseApp.Create();

Per testare lo stesso codice in locale, scarica un file JSON dell'account di servizio e imposta la variabile di ambiente GOOGLE_APPLICATION_CREDENTIALS in modo che punti ad esso.

Se Firebase Admin SDK deve rilevare una stringa ID account di servizio, lo fa quando il tuo codice crea un token personalizzato per la prima volta. Il risultato viene memorizzato nella cache e riutilizzato per le successive operazioni di firma del token. L'ID account di servizio rilevato automaticamente è in genere uno degli account di servizio predefiniti forniti da Google Cloud:

Proprio come con gli ID account di servizio specificati in modo esplicito, gli ID account di servizio rilevati automaticamente devono disporre dell'autorizzazione iam.serviceAccounts.signBlob affinché la creazione del token personalizzato funzioni. Potrebbe essere necessario utilizzare la sezione IAM e amministratore di Google Cloud Console per concedere agli account di servizio predefiniti le autorizzazioni necessarie. Per ulteriori dettagli, vedere la sezione relativa alla risoluzione dei problemi di seguito.

Utilizzo di un ID account di servizio

Per mantenere la coerenza tra le varie parti dell'applicazione, puoi specificare un ID account di servizio le cui chiavi verranno utilizzate per firmare i token durante l'esecuzione in un ambiente gestito da Google. Ciò può rendere le policy IAM più semplici e sicure ed evitare di dover includere il file JSON dell'account di servizio nel codice.

L'ID dell'account di servizio può essere trovato in Google Cloud Console o nel campo client_email di un file JSON dell'account di servizio scaricato. Gli ID account di servizio sono indirizzi e-mail che hanno il seguente formato: <client-id>@<project-id>.iam.gserviceaccount.com . Identificano in modo univoco gli account di servizio nei progetti Firebase e Google Cloud.

Per creare token personalizzati utilizzando un ID account di servizio separato, inizializzare l'SDK come mostrato di seguito:

Node.js

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

Giava

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

Pitone

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

andare

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

Gli ID account di servizio non sono informazioni riservate e pertanto la loro esposizione non ha conseguenze. Tuttavia, per firmare token personalizzati con l'account di servizio specificato, Firebase Admin SDK deve richiamare un servizio remoto. Inoltre, devi anche assicurarti che l'account di servizio utilizzato dall'Admin SDK per effettuare questa chiamata, in genere {project-name}@appspot.gserviceaccount.com, iam.serviceAccounts.signBlob dell'autorizzazione {project-name}@appspot.gserviceaccount.com . Per ulteriori dettagli, vedere la sezione relativa alla risoluzione dei problemi di seguito.

Crea token personalizzati utilizzando Firebase Admin SDK

Firebase Admin SDK ha un metodo integrato per la creazione di token personalizzati. Come minimo, devi fornire un uid , che può essere qualsiasi stringa ma dovrebbe identificare in modo univoco l'utente o il dispositivo che stai autenticando. Questi token scadono dopo un'ora.

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

Giava

String uid = "some-uid";

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

Pitone

uid = 'some-uid'

custom_token = auth.create_custom_token(uid)

andare

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

È anche possibile, facoltativamente, specificare attestazioni aggiuntive da includere nel token personalizzato. Ad esempio, di seguito, al token personalizzato è stato aggiunto un campo premiumAccount , che sarà disponibile negli oggetti auth / request.auth nelle Regole di sicurezza:

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

Giava

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

Pitone

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

custom_token = auth.create_custom_token(uid, additional_claims)

andare

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

Nomi di token personalizzati riservati

Accedi utilizzando token personalizzati sui client

Dopo aver creato un token personalizzato, dovresti inviarlo all'app client. L'app client si autentica con il token personalizzato chiamando signInWithCustomToken() :

iOS+

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

Androide

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

Unità

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

Se l'autenticazione ha esito positivo, l'utente verrà ora connesso all'app client con l'account specificato uid incluso nel token personalizzato. Se tale account non esisteva in precedenza, verrà creato un record per quell'utente.

Come con altri metodi di accesso (come signInWithEmailAndPassword() e signInWithCredential() ), l'oggetto auth nelle regole del database in tempo reale e l'oggetto request.auth nelle regole di sicurezza di Cloud Storage verranno popolati con l' uid dell'utente. In questo caso, l' uid sarà quello che hai specificato durante la generazione del token personalizzato.

Regole del database

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

Regole di conservazione

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

Se il token personalizzato contiene attestazioni aggiuntive, è possibile fare riferimento auth.token (Firebase Realtime Database) o request.auth.token (Cloud Storage) nelle regole:

Regole del database

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

Regole di conservazione

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

Crea token personalizzati utilizzando una libreria JWT di terze parti

Se il tuo back-end è in una lingua che non dispone di un SDK di amministrazione Firebase ufficiale, puoi comunque creare manualmente token personalizzati. Innanzitutto, trova una libreria JWT di terze parti per la tua lingua. Quindi, usa quella libreria JWT per coniare un JWT che include le seguenti affermazioni:

Reclami di token personalizzati
alg Algoritmo "RS256"
iss Emittente L'indirizzo email dell'account di servizio del tuo progetto
sub Materia L'indirizzo email dell'account di servizio del tuo progetto
aud Pubblico "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit"
iat Rilasciato al momento L'ora corrente, in secondi dall'epoca UNIX
exp Data di scadenza Il tempo, in secondi dall'epoca UNIX, in cui scade il token. Può essere un massimo di 3600 secondi più tardi di iat .
Nota: questo controlla solo il tempo in cui scade il token personalizzato stesso. Ma una volta che accedi a un utente utilizzando signInWithCustomToken() , questi rimarrà connesso al dispositivo fino a quando la sua sessione non sarà invalidata o l'utente non si disconnetterà.
uid L'identificatore univoco dell'utente che ha eseguito l'accesso deve essere una stringa, di lunghezza compresa tra 1 e 36 caratteri
claims (facoltativo) Affermazioni personalizzate facoltative da includere nelle variabili auth / request.auth delle regole di sicurezza

Di seguito sono riportati alcuni esempi di implementazioni su come creare token personalizzati in una varietà di lingue non supportate da Firebase Admin SDK:

PHP

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

Rubino

Usando 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

Dopo aver creato il token personalizzato, invialo all'app client per utilizzarlo per l'autenticazione con Firebase. Vedere gli esempi di codice sopra per come eseguire questa operazione.

Risoluzione dei problemi

Questa sezione illustra alcuni problemi comuni che gli sviluppatori possono incontrare durante la creazione di token personalizzati e come risolverli.

API IAM non abilitata

Se stai specificando un ID account di servizio per la firma dei token, potresti ricevere un errore simile al seguente:

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 utilizza l' API IAM per firmare i token. Questo errore indica che l'API IAM non è attualmente abilitata per il tuo progetto Firebase. Apri il collegamento nel messaggio di errore in un browser web e fai clic sul pulsante "Abilita API" per abilitarlo per il tuo progetto.

L'account di servizio non dispone delle autorizzazioni richieste

Se l'account di servizio in esecuzione su Firebase Admin SDK non dispone dell'autorizzazione iam.serviceAccounts.signBlob , è possibile che venga visualizzato un messaggio di errore simile al seguente:

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

Il modo più semplice per risolvere questo problema è concedere il ruolo IAM "Creatore token account di servizio" all'account di servizio in questione, in genere {project-name}@appspot.gserviceaccount.com :

  1. Apri l' IAM e la pagina di amministrazione in Google Cloud Console.
  2. Seleziona il tuo progetto e fai clic su "Continua".
  3. Fare clic sull'icona di modifica corrispondente all'account di servizio che si desidera aggiornare.
  4. Fare clic su "Aggiungi un altro ruolo".
  5. Digita "Service Account Token Creator" nel filtro di ricerca e selezionalo dai risultati.
  6. Fare clic su "Salva" per confermare la concessione del ruolo.

Fare riferimento alla documentazione IAM per maggiori dettagli su questo processo o imparare come aggiornare i ruoli utilizzando gli strumenti della riga di comando di gcloud.

Impossibile determinare l'account di servizio

Se ricevi un messaggio di errore simile al seguente, Firebase Admin SDK non è stato inizializzato correttamente.

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

Se ti affidi all'SDK per rilevare automaticamente un ID account di servizio, assicurati che il codice sia distribuito in un ambiente Google gestito con un server di metadati. In caso contrario, assicurati di specificare il file JSON dell'account di servizio o l'ID account di servizio durante l'inizializzazione dell'SDK.