Firebase ti offre il controllo completo sull'autenticazione consentendoti di autenticare utenti o dispositivi utilizzando token web JSON (JWT) sicuri. Generi tu
questi token sul tuo server, ritrasmetteli a un dispositivo client e quindi usa
di autenticarli con il metodo signInWithCustomToken()
.
Per farlo, devi creare un endpoint del server che accetti le credenziali di accesso, ad esempio un nome utente e una password, e, se le credenziali sono valide, restituisce un JWT personalizzato. Il token JWT personalizzato restituito dal server può essere utilizzato da un dispositivo client per l'autenticazione con Firebase (iOS e versioni successive, Android,
web). Una volta autenticata, questa identità verrà utilizzata per accedere ad altri servizi Firebase, come Firebase Realtime Database
e Cloud Storage. Inoltre, i contenuti del JWT saranno
disponibile nell'oggetto auth
in
Realtime Database Security Rules e
request.auth
oggetto in
Cloud Storage Security Rules.
Puoi creare un token personalizzato con l'SDK Firebase Admin o utilizzare una libreria JWT di terze parti se il tuo server è scritto in un linguaggio non supportato nativamente da Firebase.
Prima di iniziare
I token personalizzati sono JWT firmati a cui appartiene la chiave privata utilizzata per la firma un account di servizio Google. Esistono diversi modi per specificare il servizio Google che deve essere utilizzato dall'SDK Admin Firebase per la firma di token:
- Utilizzo di un file JSON dell'account di servizio: questo metodo può essere utilizzato in qualsiasi ambiente, ma richiede di pacchettizzare un file JSON dell'account di servizio insieme al codice. È necessario prestare particolare attenzione per assicurarsi che il file JSON dell'account di servizio non sia esposto a terze parti.
- Consentire all'SDK Admin di rilevare un account di servizio: questo metodo può essere utilizzato in ambienti gestiti da Google, come Google Cloud Functions e App Engine. Potresti dover configurare autorizzazioni aggiuntive tramite la console Google Cloud.
- 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 Console Google Cloud.
Utilizzo di un file JSON dell'account di servizio
I file JSON dell'account di servizio contengono tutte le informazioni corrispondenti al servizio (compresa la chiave privata RSA). Possono essere scaricati dalla console Firebase. Segui la configurazione dell'SDK Admin istruzioni per ulteriori informazioni su come inizializzare SDK Admin con un file JSON dell'account di servizio.
Questo metodo di inizializzazione è adatto a un'ampia gamma di SDK Admin deployment di machine learning. Consente inoltre all'SDK Admin di creare e firmare token personalizzati in locale, senza effettuare chiamate API remote. Lo svantaggio principale di questo approccio è che richiede di pacchettizzare un file JSON dell'account di servizio insieme al codice. Tieni inoltre presente che la chiave privata in un account di servizio Il file JSON contiene informazioni sensibili, pertanto è necessario prestare particolare attenzione confidenzialità. In particolare, evita di aggiungere file JSON degli account di servizio al controllo della versione pubblica.
Consentire all'SDK Admin di rilevare un account di servizio
Se il codice viene implementato in un ambiente gestito da Google, l'SDK Admin può tentare di rilevare automaticamente un modo per firmare i token personalizzati:
Se il deployment del codice viene eseguito nell'ambiente standard App Engine per Java, Python o Go, l'SDK Admin può utilizzare Servizio di identità app presenti nell'ambiente per firmare token personalizzati. Il servizio App Identity firma i dati utilizzando un account di servizio di cui è stato eseguito il provisioning per la tua app dall'app Google di ricerca.
Se il deployment del codice è stato eseguito in un altro ambiente gestito (ad es. Google Cloud) Functions, Google Compute Engine), l'SDK Admin Firebase può rilevare automaticamente la stringa dell'ID dell'account di servizio server metadati. L'ID dell'account di servizio rilevato viene quindi utilizzato insieme al campo IAM per firmare i token da 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();
Java
FirebaseApp.initializeApp();
Python
default_app = firebase_admin.initialize_app()
Vai
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 il metodo
GOOGLE_APPLICATION_CREDENTIALS
variabile di ambiente per puntarla.
Se l'SDK Firebase Admin deve scoprire una stringa ID account di servizio, lo fa quando il codice crea un token personalizzato per la prima volta. Il risultato viene memorizzato nella cache e riutilizzato per le successive operazioni di firma dei token. L'ID account di servizio rilevato automaticamente è in genere uno degli account di servizio predefiniti forniti dal Google Cloud:
Proprio come per gli ID account di servizio specificati esplicitamente, il servizio con individuazione automatica
gli ID account devono disporre dell'autorizzazione iam.serviceAccounts.signBlob
per
la creazione di token personalizzati. Potresti dover utilizzare la sezione IAM e amministrazione della console Google Cloud per concedere agli account di servizio predefiniti le autorizzazioni necessarie. Per ulteriori dettagli, consulta la sezione relativa alla risoluzione dei problemi riportata di seguito.
Utilizzo di un ID account di servizio
Per mantenere la coerenza tra le varie parti dell'applicazione, puoi specifica un ID account di servizio le cui chiavi verranno utilizzate per firmare i token durante l'esecuzione in un ambiente gestito da Google. In questo modo, i criteri IAM possono essere semplificati e resi più sicuri ed è possibile evitare di dover includere il file JSON dell'account di servizio nel codice.
L'ID dell'account di servizio è disponibile nella
Console Google Cloud,
o nel campo client_email
di un file JSON dell'account di servizio scaricato.
Gli ID account di servizio sono indirizzi email con 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, inizializza l'SDK come mostrato di seguito:
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)
Vai
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 degli account di servizio non sono informazioni sensibili e pertanto la loro esposizione è irrilevante. Tuttavia, per firmare i token personalizzati con l'account di servizio specificato, l'SDK Firebase Admin deve invocare un servizio remoto.
Devi inoltre assicurarti che l'account di servizio di SDK Admin
per effettuare questa chiamata
-di solito {project-name}@appspot.gserviceaccount.com
-
ha il iam.serviceAccounts.signBlob
autorizzazione.
Per ulteriori dettagli, consulta la sezione sulla risoluzione dei problemi di seguito.
Creare token personalizzati utilizzando l'SDK Admin Firebase
L'SDK Firebase Admin dispone di un metodo integrato per la creazione di token personalizzati. Alle ore
minimo, devi fornire un valore uid
, che può essere qualsiasi stringa ma
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);
});
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)
Vai
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
Facoltativamente, puoi specificare ulteriori rivendicazioni da includere nel
di accesso. Ad esempio, di seguito è stato aggiunto un campo premiumAccount
al token personalizzato, 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);
});
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)
Vai
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 dei token personalizzati riservati
Accedere utilizzando token personalizzati sui client
Dopo aver creato un token personalizzato, devi inviarlo all'app client. L'app client si autentica con il token personalizzato chiamandosignInWithCustomToken()
:
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);
}
}
});
Unity
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;
// ...
});
Se l'autenticazione ha esito positivo, l'utente accederà ora al tuo
l'app client con l'account specificato da uid
incluso nel
di accesso. Se l'account non esisteva in precedenza, verrà creato un record per quell'utente
è stato creato.
Come per altri metodi di accesso (ad esempio signInWithEmailAndPassword()
e signInWithCredential()
), l'oggetto auth
nel Realtime Database Security Rules e l'oggetto request.auth
nel Cloud Storage Security Rules verranno compilati con il uid
dell'utente. In questo caso, sarà uid
specificato durante la generazione del token personalizzato.
Regole del database
{
"rules": {
"adminContent": {
".read": "auth.uid === 'some-uid'"
}
}
}
Regole di archiviazione
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 richieste aggiuntive, è possibile farvi riferimento
auth.token
(Firebase Realtime Database) o request.auth.token
(Cloud Storage) nelle tue regole:
Regole del database
{
"rules": {
"premiumContent": {
".read": "auth.token.premiumAccount === true"
}
}
}
Regole di archiviazione
service firebase.storage {
match /b/<your-firebase-storage-bucket>/o {
match /premiumContent/{filename} {
allow read, write: if request.auth.token.premiumAccount == true;
}
}
}
Creare token personalizzati utilizzando una libreria JWT di terze parti
Se il backend è in una lingua che non ha un amministratore Firebase ufficiale SDK, puoi comunque creare manualmente token personalizzati. Innanzitutto, trova una libreria JWT di terze parti per la tua lingua. Poi, utilizza la libreria JWT per coniare un JWT che includa le seguenti attestazioni:
Attestazioni token personalizzati | ||
---|---|---|
alg |
Algoritmo | "RS256" |
iss |
Emittente | Indirizzo email dell'account di servizio del progetto |
sub |
Oggetto | Indirizzo email dell'account di servizio del progetto |
aud |
Pubblico | "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit" |
iat |
Data/ora di emissione | L'ora attuale, in secondi dall'epoca di UNIX. |
exp |
Scadenza |
Il tempo, in secondi, dall'epoca UNIX, in cui scade il token. Deve essere al massimo 3600 secondi dopo il iat .
Nota: questo controlla solo la data di scadenza del token personalizzato stesso. Tuttavia, una volta che un utente esegue l'accesso utilizzando signInWithCustomToken() , manterranno l'accesso al
dispositivo finché la sessione non viene invalidata o l'utente si disconnette.
|
uid |
L'identificatore univoco dell'utente che ha eseguito l'accesso deve essere una stringa, compresa tra
Lunghezza compresa tra 1 e 128 caratteri, inclusi. I uid più brevi offrono un rendimento migliore.
|
|
claims (facoltativo) |
Dichiarazioni personalizzate facoltative da includere nelle variabili auth /
request.auth delle regole di sicurezza
|
Di seguito sono riportati alcuni esempi di implementazione di come creare token personalizzati in una serie di lingue non supportate dall'SDK Firebase Admin:
PHP
In 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
In 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 autenticarsi con Firebase. Per scoprire come, consulta gli esempi di codice riportati sopra.
Risoluzione dei problemi
Questa sezione illustra alcuni problemi comuni che gli sviluppatori potrebbero riscontrare quando creando token personalizzati e spiegando come risolverli.
API IAM non abilitata
Se specifichi 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.
L'SDK Firebase Admin utilizza l'API IAM per firmare i token. Questo errore indica che l'API IAM non è attualmente abilitata per il tuo progetto Firebase. Apri in un browser web il link contenuto nel messaggio di errore 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 con cui viene eseguito l'SDK Firebase Admin non dispone dell'autorizzazioneiam.serviceAccounts.signBlob
, potresti visualizzare 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 il problema è concedere il ruolo IAM "Creatore token account di servizio" all'account di servizio in questione, in genere{project-name}@appspot.gserviceaccount.com
:
- Apri la pagina IAM e amministrazione nella console Google Cloud.
- Seleziona il progetto e fai clic su "Continua".
- Fai clic sull'icona di modifica corrispondente all'account di servizio che vuoi aggiornare.
- Fai clic su "Aggiungi un altro ruolo".
- Digita "Creatore token account di servizio" nel filtro di ricerca e selezionare dai risultati.
- Fai clic su "Salva" per confermare l'assegnazione del ruolo.
Consulta la documentazione IAM per ulteriori dettagli su questa procedura o scopri come aggiornare i ruoli utilizzando il a riga di comando gcloud.
Impossibile determinare l'account di servizio
Se ricevi un messaggio di errore simile al seguente, l'SDK Firebase Admin 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 utilizzi l'SDK per il rilevamento automatico dell'ID account di servizio, assicurati il deployment del codice viene eseguito 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 all'inizializzazione dell'SDK.