Autenticati con Firebase utilizzando il collegamento e-mail in Android

Puoi utilizzare Firebase Authentication per accedere a un utente inviandogli un'e-mail contenente un collegamento, su cui può fare clic per accedere. Nel processo, viene verificato anche l'indirizzo e-mail dell'utente.

Ci sono numerosi vantaggi per l'accesso tramite e-mail:

  • Registrazione e accesso a basso attrito.
  • Riduzione del rischio di riutilizzo della password tra le applicazioni, che può compromettere la sicurezza anche di password ben selezionate.
  • La capacità di autenticare un utente verificando anche che l'utente sia il legittimo proprietario di un indirizzo email.
  • Un utente ha bisogno solo di un account e-mail accessibile per accedere. Non è richiesta la proprietà di un numero di telefono o di un account di social media.
  • Un utente può accedere in modo sicuro senza la necessità di fornire (o ricordare) una password, che può essere ingombrante su un dispositivo mobile.
  • Un utente esistente che ha effettuato l'accesso in precedenza con un identificatore di posta elettronica (password o federato) può essere aggiornato per accedere solo con l'e-mail. Ad esempio, un utente che ha dimenticato la password può comunque accedere senza dover reimpostare la password.

Prima di iniziare

Configura il tuo progetto Android

  1. Se non l'hai già fatto, aggiungi Firebase al tuo progetto Android .

  2. Nel file Gradle del tuo modulo (a livello di app) (di solito <project>/<app-module>/build.gradle.kts o <project>/<app-module>/build.gradle ), aggiungi la dipendenza per l'autenticazione Firebase Libreria Android. Ti consigliamo di utilizzare la distinta base Android di Firebase per controllare il controllo delle versioni della libreria.

    Inoltre, come parte della configurazione dell'autenticazione Firebase, devi aggiungere l'SDK dei servizi di Google Play alla tua app.

    Kotlin+KTX

    dependencies {
        // Import the BoM for the Firebase platform
        implementation(platform("com.google.firebase:firebase-bom:32.3.1"))
    
        // Add the dependency for the Firebase Authentication library
        // When using the BoM, you don't specify versions in Firebase library dependencies
        implementation("com.google.firebase:firebase-auth-ktx")
    // Also add the dependency for the Google Play services library and specify its version implementation("com.google.android.gms:play-services-auth:20.7.0")
    }

    Utilizzando Firebase Android BoM , la tua app utilizzerà sempre versioni compatibili delle librerie Firebase Android.

    (Alternativa) Aggiungi le dipendenze della libreria Firebase senza utilizzare la distinta base

    Se scegli di non utilizzare Firebase BoM, devi specificare ogni versione della libreria Firebase nella relativa riga di dipendenza.

    Tieni presente che se utilizzi più librerie Firebase nella tua app, ti consigliamo vivamente di utilizzare la distinta base per gestire le versioni della libreria, che garantisce che tutte le versioni siano compatibili.

    dependencies {
        // Add the dependency for the Firebase Authentication library
        // When NOT using the BoM, you must specify versions in Firebase library dependencies
        implementation("com.google.firebase:firebase-auth-ktx:22.1.2")
    // Also add the dependency for the Google Play services library and specify its version implementation("com.google.android.gms:play-services-auth:20.7.0")
    }

    Java

    dependencies {
        // Import the BoM for the Firebase platform
        implementation(platform("com.google.firebase:firebase-bom:32.3.1"))
    
        // Add the dependency for the Firebase Authentication library
        // When using the BoM, you don't specify versions in Firebase library dependencies
        implementation("com.google.firebase:firebase-auth")
    // Also add the dependency for the Google Play services library and specify its version implementation("com.google.android.gms:play-services-auth:20.7.0")
    }

    Utilizzando Firebase Android BoM , la tua app utilizzerà sempre versioni compatibili delle librerie Firebase Android.

    (Alternativa) Aggiungi le dipendenze della libreria Firebase senza utilizzare la distinta base

    Se scegli di non utilizzare Firebase BoM, devi specificare ogni versione della libreria Firebase nella relativa riga di dipendenza.

    Tieni presente che se utilizzi più librerie Firebase nella tua app, ti consigliamo vivamente di utilizzare la distinta base per gestire le versioni della libreria, che garantisce che tutte le versioni siano compatibili.

    dependencies {
        // Add the dependency for the Firebase Authentication library
        // When NOT using the BoM, you must specify versions in Firebase library dependencies
        implementation("com.google.firebase:firebase-auth:22.1.2")
    // Also add the dependency for the Google Play services library and specify its version implementation("com.google.android.gms:play-services-auth:20.7.0")
    }

Per accedere agli utenti tramite collegamento e-mail, devi prima abilitare il metodo di accesso al provider di posta elettronica e al collegamento e-mail per il tuo progetto Firebase:

  1. Nella console Firebase , apri la sezione Auth .
  2. Nella scheda Metodo di accesso abilitare il provider di posta elettronica/password . Tieni presente che l'accesso tramite e-mail/password deve essere abilitato per utilizzare l'accesso tramite collegamento e-mail.
  3. Nella stessa sezione, abilita il metodo di accesso tramite collegamento e-mail (accesso senza password) .
  4. Fare clic su Salva .

Per avviare il flusso di autenticazione, presenta all'utente un'interfaccia che richiede all'utente di fornire il proprio indirizzo e-mail e quindi chiama sendSignInLinkToEmail per richiedere a Firebase di inviare il collegamento di autenticazione all'e-mail dell'utente.

  1. Costruisci l'oggetto ActionCodeSettings , che fornisce a Firebase le istruzioni su come costruire il collegamento e-mail. Imposta i seguenti campi:

    • url : il deep link da incorporare e qualsiasi stato aggiuntivo da trasmettere. Il dominio del collegamento deve essere inserito nella whitelist nell'elenco dei domini autorizzati della Console Firebase, che può essere trovato accedendo alla scheda Metodo di accesso (Autenticazione -> Metodo di accesso). Il collegamento reindirizzerà l'utente a questo URL se l'app non è installata sul proprio dispositivo e non è stato possibile installare l'app.
    • androidPackageName e IOSBundleId : le app da usare quando il collegamento di accesso viene aperto su un dispositivo Android o Apple. Scopri di più su come configurare Firebase Dynamic Links per aprire i link di azioni email tramite app mobili.
    • handleCodeInApp : impostato su true. L'operazione di accesso deve essere sempre completata nell'app a differenza di altre azioni e-mail fuori banda (reimpostazione password e verifiche e-mail). Questo perché, alla fine del flusso, è previsto che l'utente abbia effettuato l'accesso e il suo stato di autenticazione sia stato mantenuto all'interno dell'app.
    • dynamicLinkDomain : quando vengono definiti più domini di collegamento dinamico personalizzati per un progetto, specificare quale utilizzare quando il collegamento deve essere aperto tramite un'app per dispositivi mobili specificata (ad esempio, example.page.link ). Altrimenti viene selezionato automaticamente il primo dominio.

    Kotlin+KTX

    val actionCodeSettings = actionCodeSettings {
        // URL you want to redirect back to. The domain (www.example.com) for this
        // URL must be whitelisted in the Firebase Console.
        url = "https://www.example.com/finishSignUp?cartId=1234"
        // This must be true
        handleCodeInApp = true
        setIOSBundleId("com.example.ios")
        setAndroidPackageName(
            "com.example.android",
            true, // installIfNotAvailable
            "12", // minimumVersion
        )
    }

    Java

    ActionCodeSettings actionCodeSettings =
            ActionCodeSettings.newBuilder()
                    // URL you want to redirect back to. The domain (www.example.com) for this
                    // URL must be whitelisted in the Firebase Console.
                    .setUrl("https://www.example.com/finishSignUp?cartId=1234")
                    // This must be true
                    .setHandleCodeInApp(true)
                    .setIOSBundleId("com.example.ios")
                    .setAndroidPackageName(
                            "com.example.android",
                            true, /* installIfNotAvailable */
                            "12"    /* minimumVersion */)
                    .build();

    Per ulteriori informazioni su ActionCodeSettings, fare riferimento alla sezione Passing State in Email Actions .

  2. Chiedi all'utente la sua email.

  3. Invia il collegamento di autenticazione all'e-mail dell'utente e salva l'e-mail dell'utente nel caso in cui l'utente completi l'accesso tramite e-mail sullo stesso dispositivo.

    Kotlin+KTX

    Firebase.auth.sendSignInLinkToEmail(email, actionCodeSettings)
        .addOnCompleteListener { task ->
            if (task.isSuccessful) {
                Log.d(TAG, "Email sent.")
            }
        }

    Java

    FirebaseAuth auth = FirebaseAuth.getInstance();
    auth.sendSignInLinkToEmail(email, actionCodeSettings)
            .addOnCompleteListener(new OnCompleteListener<Void>() {
                @Override
                public void onComplete(@NonNull Task<Void> task) {
                    if (task.isSuccessful()) {
                        Log.d(TAG, "Email sent.");
                    }
                }
            });

Problemi di sicurezza

Per evitare che un link di accesso venga utilizzato per accedere come utente non autorizzato o su un dispositivo non previsto, Firebase Auth richiede che venga fornito l'indirizzo email dell'utente al completamento del flusso di accesso. Affinché l'accesso abbia esito positivo, questo indirizzo e-mail deve corrispondere all'indirizzo a cui è stato originariamente inviato il collegamento di accesso.

Puoi semplificare questo flusso per gli utenti che aprono il collegamento di accesso sullo stesso dispositivo a cui richiedono il collegamento, memorizzando il loro indirizzo e-mail localmente, ad esempio utilizzando SharedPreferences, quando invii l'e-mail di accesso. Quindi, utilizza questo indirizzo per completare il flusso. Non passare l'e-mail dell'utente nei parametri dell'URL di reindirizzamento e riutilizzarla in quanto ciò potrebbe abilitare le iniezioni di sessione.

Dopo il completamento dell'accesso, qualsiasi precedente meccanismo di accesso non verificato verrà rimosso dall'utente e tutte le sessioni esistenti verranno invalidate. Ad esempio, se qualcuno ha precedentemente creato un account non verificato con la stessa e-mail e password, la password dell'utente verrà rimossa per impedire all'imitatore che ha rivendicato la proprietà e creato l'account non verificato di accedere nuovamente con l'e-mail e la password non verificate.

Assicurati inoltre di utilizzare un URL HTTPS in produzione per evitare che il tuo collegamento venga potenzialmente intercettato da server intermedi.

Completamento dell'accesso in un'app Android

Firebase Authentication utilizza Firebase Dynamic Links per inviare il collegamento e-mail a un dispositivo mobile. Per il completamento dell'accesso tramite l'applicazione per dispositivi mobili, l'applicazione deve essere configurata per rilevare il collegamento dell'applicazione in entrata, analizzare il collegamento profondo sottostante e quindi completare l'accesso.

Firebase Auth utilizza Firebase Dynamic Links quando invia un collegamento che deve essere aperto in un'applicazione mobile. Per utilizzare questa funzione, i collegamenti dinamici devono essere configurati nella console di Firebase.

  1. Abilita collegamenti dinamici Firebase:

    1. Nella console Firebase , apri la sezione Collegamenti dinamici .
    2. Se non hai ancora accettato i termini di Dynamic Links e creato un dominio Dynamic Links, fallo ora.

      Se hai già creato un dominio Dynamic Links, prendine nota. Un dominio Dynamic Links in genere è simile al seguente esempio:

      example.page.link

      Avrai bisogno di questo valore quando configuri la tua app Apple o Android per intercettare il collegamento in entrata.

  2. Configurazione delle applicazioni Android:

    1. Per gestire questi collegamenti dalla tua applicazione Android, il nome del pacchetto Android deve essere specificato nelle impostazioni del progetto Firebase Console. Inoltre, è necessario fornire SHA-1 e SHA-256 del certificato dell'applicazione.
    2. Ora che hai aggiunto un dominio di collegamento dinamico e ti sei assicurato che la tua app Android sia configurata correttamente, il collegamento dinamico reindirizzerà alla tua applicazione, a partire dall'attività di avvio.
    3. Se desideri che il collegamento dinamico reindirizzi a un'attività specifica, dovrai configurare un filtro intent nel tuo file AndroidManifest.xml . Questo può essere fatto specificando il tuo dominio di collegamento dinamico o il gestore dell'azione email nel filtro intent. Per impostazione predefinita, il gestore dell'azione email è ospitato su un dominio come nell'esempio seguente:
      PROJECT_ID.firebaseapp.com/
    4. Avvertenze:
      1. Non specificare l'URL che hai impostato su actionCodeSettings nel tuo filtro intent.
      2. Durante la creazione del tuo dominio di collegamento dinamico potresti aver creato anche un breve collegamento URL. Questo breve URL non verrà passato; non configurare il filtro intent per rilevarlo con un attributo android:pathPrefix . Ciò significa che non sarai in grado di rilevare collegamenti dinamici diversi in parti diverse della tua applicazione. Tuttavia, puoi controllare il parametro di query mode nel collegamento per vedere quale operazione si sta tentando di eseguire oppure utilizzare i metodi SDK come isSignInWithEmailLink per vedere se un collegamento che la tua app ha ricevuto fa ciò che desideri.
    5. Per ulteriori informazioni sulla ricezione di collegamenti dinamici, fare riferimento alle istruzioni sulla ricezione di collegamenti dinamici Android .

Dopo aver ricevuto il collegamento come descritto sopra, verificare che sia destinato all'autenticazione del collegamento e-mail e completare l'accesso.

Kotlin+KTX

val auth = Firebase.auth
val intent = intent
val emailLink = intent.data.toString()

// Confirm the link is a sign-in with email link.
if (auth.isSignInWithEmailLink(emailLink)) {
    // Retrieve this from wherever you stored it
    val email = "someemail@domain.com"

    // The client SDK will parse the code from the link for you.
    auth.signInWithEmailLink(email, emailLink)
        .addOnCompleteListener { task ->
            if (task.isSuccessful) {
                Log.d(TAG, "Successfully signed in with email link!")
                val result = task.result
                // You can access the new user via result.getUser()
                // Additional user info profile *not* available via:
                // result.getAdditionalUserInfo().getProfile() == null
                // You can check if the user is new or existing:
                // result.getAdditionalUserInfo().isNewUser()
            } else {
                Log.e(TAG, "Error signing in with email link", task.exception)
            }
        }
}

Java

FirebaseAuth auth = FirebaseAuth.getInstance();
Intent intent = getIntent();
String emailLink = intent.getData().toString();

// Confirm the link is a sign-in with email link.
if (auth.isSignInWithEmailLink(emailLink)) {
    // Retrieve this from wherever you stored it
    String email = "someemail@domain.com";

    // The client SDK will parse the code from the link for you.
    auth.signInWithEmailLink(email, emailLink)
            .addOnCompleteListener(new OnCompleteListener<AuthResult>() {
                @Override
                public void onComplete(@NonNull Task<AuthResult> task) {
                    if (task.isSuccessful()) {
                        Log.d(TAG, "Successfully signed in with email link!");
                        AuthResult result = task.getResult();
                        // You can access the new user via result.getUser()
                        // Additional user info profile *not* available via:
                        // result.getAdditionalUserInfo().getProfile() == null
                        // You can check if the user is new or existing:
                        // result.getAdditionalUserInfo().isNewUser()
                    } else {
                        Log.e(TAG, "Error signing in with email link", task.getException());
                    }
                }
            });
}

Per ulteriori informazioni su come gestire l'accesso con collegamento e-mail in un'applicazione Apple, consulta la guida alle piattaforme Apple .

Per informazioni su come gestire l'accesso con collegamento e-mail in un'applicazione Web, fare riferimento alla Guida Web .

Puoi anche collegare questo metodo di autenticazione a un utente esistente. Ad esempio, un utente precedentemente autenticato con un altro provider, ad esempio un numero di telefono, può aggiungere questo metodo di accesso al proprio account esistente.

La differenza sarebbe nella seconda metà dell'operazione:

Kotlin+KTX

// Construct the email link credential from the current URL.
val credential = EmailAuthProvider.getCredentialWithLink(email, emailLink)

// Link the credential to the current user.
Firebase.auth.currentUser!!.linkWithCredential(credential)
    .addOnCompleteListener { task ->
        if (task.isSuccessful) {
            Log.d(TAG, "Successfully linked emailLink credential!")
            val result = task.result
            // You can access the new user via result.getUser()
            // Additional user info profile *not* available via:
            // result.getAdditionalUserInfo().getProfile() == null
            // You can check if the user is new or existing:
            // result.getAdditionalUserInfo().isNewUser()
        } else {
            Log.e(TAG, "Error linking emailLink credential", task.exception)
        }
    }

Java

// Construct the email link credential from the current URL.
AuthCredential credential =
        EmailAuthProvider.getCredentialWithLink(email, emailLink);

// Link the credential to the current user.
auth.getCurrentUser().linkWithCredential(credential)
        .addOnCompleteListener(new OnCompleteListener<AuthResult>() {
            @Override
            public void onComplete(@NonNull Task<AuthResult> task) {
                if (task.isSuccessful()) {
                    Log.d(TAG, "Successfully linked emailLink credential!");
                    AuthResult result = task.getResult();
                    // You can access the new user via result.getUser()
                    // Additional user info profile *not* available via:
                    // result.getAdditionalUserInfo().getProfile() == null
                    // You can check if the user is new or existing:
                    // result.getAdditionalUserInfo().isNewUser()
                } else {
                    Log.e(TAG, "Error linking emailLink credential", task.getException());
                }
            }
        });

Questo può essere utilizzato anche per autenticare nuovamente un utente di collegamento e-mail prima di eseguire un'operazione riservata.

Kotlin+KTX

// Construct the email link credential from the current URL.
val credential = EmailAuthProvider.getCredentialWithLink(email, emailLink)

// Re-authenticate the user with this credential.
Firebase.auth.currentUser!!.reauthenticateAndRetrieveData(credential)
    .addOnCompleteListener { task ->
        if (task.isSuccessful) {
            // User is now successfully reauthenticated
        } else {
            Log.e(TAG, "Error reauthenticating", task.exception)
        }
    }

Java

// Construct the email link credential from the current URL.
AuthCredential credential =
        EmailAuthProvider.getCredentialWithLink(email, emailLink);

// Re-authenticate the user with this credential.
auth.getCurrentUser().reauthenticateAndRetrieveData(credential)
        .addOnCompleteListener(new OnCompleteListener<AuthResult>() {
            @Override
            public void onComplete(@NonNull Task<AuthResult> task) {
                if (task.isSuccessful()) {
                    // User is now successfully reauthenticated
                } else {
                    Log.e(TAG, "Error reauthenticating", task.getException());
                }
            }
        });

Tuttavia, poiché il flusso potrebbe finire su un dispositivo diverso in cui l'utente originale non era connesso, questo flusso potrebbe non essere completato. In tal caso, all'utente può essere mostrato un errore per costringerlo ad aprire il collegamento sullo stesso dispositivo. Alcuni stati possono essere passati nel collegamento per fornire informazioni sul tipo di operazione e sull'uid utente.

Nel caso in cui supporti sia l'accesso basato su password sia quello basato su collegamento tramite e-mail, per differenziare il metodo di accesso per un utente con password/collegamento, utilizza fetchSignInMethodsForEmail . Ciò è utile per i flussi con priorità all'identificatore in cui all'utente viene prima chiesto di fornire la propria e-mail e quindi viene presentato il metodo di accesso:

Kotlin+KTX

Firebase.auth.fetchSignInMethodsForEmail(email)
    .addOnSuccessListener { result ->
        val signInMethods = result.signInMethods!!
        if (signInMethods.contains(EmailAuthProvider.EMAIL_PASSWORD_SIGN_IN_METHOD)) {
            // User can sign in with email/password
        } else if (signInMethods.contains(EmailAuthProvider.EMAIL_LINK_SIGN_IN_METHOD)) {
            // User can sign in with email/link
        }
    }
    .addOnFailureListener { exception ->
        Log.e(TAG, "Error getting sign in methods for user", exception)
    }

Java

auth.fetchSignInMethodsForEmail(email)
        .addOnCompleteListener(new OnCompleteListener<SignInMethodQueryResult>() {
            @Override
            public void onComplete(@NonNull Task<SignInMethodQueryResult> task) {
                if (task.isSuccessful()) {
                    SignInMethodQueryResult result = task.getResult();
                    List<String> signInMethods = result.getSignInMethods();
                    if (signInMethods.contains(EmailAuthProvider.EMAIL_PASSWORD_SIGN_IN_METHOD)) {
                        // User can sign in with email/password
                    } else if (signInMethods.contains(EmailAuthProvider.EMAIL_LINK_SIGN_IN_METHOD)) {
                        // User can sign in with email/link
                    }
                } else {
                    Log.e(TAG, "Error getting sign in methods for user", task.getException());
                }
            }
        });

Come descritto sopra, email/password e email/link sono considerati lo stesso EmailAuthProvider (stesso PROVIDER_ID ) con diversi metodi di accesso.

Prossimi passi

Dopo che un utente ha effettuato l'accesso per la prima volta, viene creato un nuovo account utente e collegato alle credenziali, ovvero nome utente e password, numero di telefono o informazioni sul provider di autenticazione, con cui l'utente ha effettuato l'accesso. Questo nuovo account viene archiviato come parte del tuo progetto Firebase e può essere utilizzato per identificare un utente in ogni app del tuo progetto, indipendentemente dalla modalità di accesso dell'utente.

  • Nelle tue app puoi ottenere le informazioni di base sul profilo dell'utente dall'oggetto FirebaseUser . Vedere Gestire gli utenti .

  • In Firebase Realtime Database and Cloud Storage Security Rules , puoi ottenere l'ID utente univoco dell'utente che ha eseguito l'accesso dalla variabile auth e utilizzarlo per controllare a quali dati può accedere un utente.

Puoi consentire agli utenti di accedere alla tua app utilizzando più provider di autenticazione collegando le credenziali del provider di autenticazione a un account utente esistente.

Per disconnettere un utente, chiama signOut :

Kotlin+KTX

Firebase.auth.signOut()

Java

FirebaseAuth.getInstance().signOut();