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
Se non l'hai già fatto, copia lo snippet di inizializzazione dalla console Firebase al tuo progetto come descritto in Aggiungere Firebase al tuo progetto JavaScript .
Abilita l'accesso tramite collegamento e-mail per il tuo progetto Firebase
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:
- Nella console Firebase , apri la sezione Auth .
- 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.
- Nella stessa sezione, abilita il metodo di accesso tramite collegamento e-mail (accesso senza password) .
- Fare clic su Salva .
Invia un link di autenticazione all'indirizzo email dell'utente
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.
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 aggiunto all'elenco dei domini autorizzati della Console Firebase, che può essere trovato accedendo alla scheda Metodo di accesso (Autenticazione -> Metodo di accesso). -
android
eios
: le app da utilizzare 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.Web modular API
const actionCodeSettings = { // URL you want to redirect back to. The domain (www.example.com) for this // URL must be in the authorized domains list in the Firebase Console. url: 'https://www.example.com/finishSignUp?cartId=1234', // This must be true. handleCodeInApp: true, iOS: { bundleId: 'com.example.ios' }, android: { packageName: 'com.example.android', installApp: true, minimumVersion: '12' }, dynamicLinkDomain: 'example.page.link' };
Web namespaced API
var actionCodeSettings = { // URL you want to redirect back to. The domain (www.example.com) for this // URL must be in the authorized domains list in the Firebase Console. url: 'https://www.example.com/finishSignUp?cartId=1234', // This must be true. handleCodeInApp: true, iOS: { bundleId: 'com.example.ios' }, android: { packageName: 'com.example.android', installApp: true, minimumVersion: '12' }, dynamicLinkDomain: 'example.page.link' };
Per ulteriori informazioni su ActionCodeSettings, fare riferimento alla sezione Passing State in Email Actions .
-
Chiedi all'utente la sua email.
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.
Web modular API
import { getAuth, sendSignInLinkToEmail } from "firebase/auth"; const auth = getAuth(); sendSignInLinkToEmail(auth, email, actionCodeSettings) .then(() => { // The link was successfully sent. Inform the user. // Save the email locally so you don't need to ask the user for it again // if they open the link on the same device. window.localStorage.setItem('emailForSignIn', email); // ... }) .catch((error) => { const errorCode = error.code; const errorMessage = error.message; // ... });
Web namespaced API
firebase.auth().sendSignInLinkToEmail(email, actionCodeSettings) .then(() => { // The link was successfully sent. Inform the user. // Save the email locally so you don't need to ask the user for it again // if they open the link on the same device. window.localStorage.setItem('emailForSignIn', email); // ... }) .catch((error) => { var errorCode = error.code; var errorMessage = error.message; // ... });
Completa l'accesso con il link e-mail
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, archiviando il loro indirizzo e-mail localmente, ad esempio utilizzando localStorage o cookie, 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 una pagina Web
Il formato del collegamento diretto all'e-mail è lo stesso del formato utilizzato per le azioni e-mail fuori banda (verifica dell'e-mail, reimpostazione della password e revoca della modifica dell'e-mail). Firebase Auth semplifica questo controllo fornendo l'API isSignInWithEmailLink
per verificare se un collegamento è un collegamento di accesso con e-mail.
Per completare l'accesso alla pagina di destinazione, chiama signInWithEmailLink
con l'e-mail dell'utente e il collegamento e-mail effettivo contenente il codice monouso.
Web modular API
import { getAuth, isSignInWithEmailLink, signInWithEmailLink } from "firebase/auth"; // Confirm the link is a sign-in with email link. const auth = getAuth(); if (isSignInWithEmailLink(auth, window.location.href)) { // Additional state parameters can also be passed via URL. // This can be used to continue the user's intended action before triggering // the sign-in operation. // Get the email if available. This should be available if the user completes // the flow on the same device where they started it. let email = window.localStorage.getItem('emailForSignIn'); if (!email) { // User opened the link on a different device. To prevent session fixation // attacks, ask the user to provide the associated email again. For example: email = window.prompt('Please provide your email for confirmation'); } // The client SDK will parse the code from the link for you. signInWithEmailLink(auth, email, window.location.href) .then((result) => { // Clear email from storage. window.localStorage.removeItem('emailForSignIn'); // You can access the new user via result.user // Additional user info profile not available via: // result.additionalUserInfo.profile == null // You can check if the user is new or existing: // result.additionalUserInfo.isNewUser }) .catch((error) => { // Some error occurred, you can inspect the code: error.code // Common errors could be invalid email and invalid or expired OTPs. }); }
Web namespaced API
// Confirm the link is a sign-in with email link. if (firebase.auth().isSignInWithEmailLink(window.location.href)) { // Additional state parameters can also be passed via URL. // This can be used to continue the user's intended action before triggering // the sign-in operation. // Get the email if available. This should be available if the user completes // the flow on the same device where they started it. var email = window.localStorage.getItem('emailForSignIn'); if (!email) { // User opened the link on a different device. To prevent session fixation // attacks, ask the user to provide the associated email again. For example: email = window.prompt('Please provide your email for confirmation'); } // The client SDK will parse the code from the link for you. firebase.auth().signInWithEmailLink(email, window.location.href) .then((result) => { // Clear email from storage. window.localStorage.removeItem('emailForSignIn'); // You can access the new user via result.user // Additional user info profile not available via: // result.additionalUserInfo.profile == null // You can check if the user is new or existing: // result.additionalUserInfo.isNewUser }) .catch((error) => { // Some error occurred, you can inspect the code: error.code // Common errors could be invalid email and invalid or expired OTPs. }); }
Completamento dell'accesso in un'app per dispositivi mobili
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 diretto sottostante e quindi completare l'accesso come avviene tramite il flusso web.
Per ulteriori informazioni su come gestire l'accesso con il collegamento e-mail in un'applicazione Android, fare riferimento alla guida di Android .
Per saperne di più su come gestire l'accesso con collegamento e-mail in un'applicazione Apple, fare riferimento alla guida delle piattaforme Apple .
Collegamento/riautenticazione con collegamento e-mail
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:
Web modular API
import { getAuth, linkWithCredential, EmailAuthProvider } from "firebase/auth"; // Construct the email link credential from the current URL. const credential = EmailAuthProvider.credentialWithLink( email, window.location.href); // Link the credential to the current user. const auth = getAuth(); linkWithCredential(auth.currentUser, credential) .then((usercred) => { // The provider is now successfully linked. // The phone user can now sign in with their phone number or email. }) .catch((error) => { // Some error occurred. });
Web namespaced API
// Construct the email link credential from the current URL. var credential = firebase.auth.EmailAuthProvider.credentialWithLink( email, window.location.href); // Link the credential to the current user. firebase.auth().currentUser.linkWithCredential(credential) .then((usercred) => { // The provider is now successfully linked. // The phone user can now sign in with their phone number or email. }) .catch((error) => { // Some error occurred. });
Questo può essere utilizzato anche per autenticare nuovamente un utente di collegamento e-mail prima di eseguire un'operazione riservata.
Web modular API
import { getAuth, reauthenticateWithCredential, EmailAuthProvider } from "firebase/auth"; // Construct the email link credential from the current URL. const credential = EmailAuthProvider.credentialWithLink( email, window.location.href); // Re-authenticate the user with this credential. const auth = getAuth(); reauthenticateWithCredential(auth.currentUser, credential) .then((usercred) => { // The user is now successfully re-authenticated and can execute sensitive // operations. }) .catch((error) => { // Some error occurred. });
Web namespaced API
// Construct the email link credential from the current URL. var credential = firebase.auth.EmailAuthProvider.credentialWithLink( email, window.location.href); // Re-authenticate the user with this credential. firebase.auth().currentUser.reauthenticateWithCredential(credential) .then((usercred) => { // The user is now successfully re-authenticated and can execute sensitive // operations. }) .catch((error) => { // Some error occurred. });
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.
Differenziare e-mail/password dal collegamento e-mail
Nel caso in cui supporti sia l'accesso tramite password che 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:
Web modular API
import { getAuth, fetchSignInMethodsForEmail, EmailAuthProvider} from "firebase/auth"; // After asking the user for their email. const email = window.prompt('Please provide your email'); const auth = getAuth(); fetchSignInMethodsForEmail(auth, email) .then((signInMethods) => { // This returns the same array as fetchProvidersForEmail but for email // provider identified by 'password' string, signInMethods would contain 2 // different strings: // 'emailLink' if the user previously signed in with an email/link // 'password' if the user has a password. // A user could have both. if (signInMethods.indexOf(EmailAuthProvider.EMAIL_PASSWORD_SIGN_IN_METHOD) != -1) { // User can sign in with email/password. } if (signInMethods.indexOf(EmailAuthProvider.EMAIL_LINK_SIGN_IN_METHOD) != -1) { // User can sign in with email/link. } }) .catch((error) => { // Some error occurred, you can inspect the code: error.code });
Web namespaced API
// After asking the user for their email. var email = window.prompt('Please provide your email'); firebase.auth().fetchSignInMethodsForEmail(email) .then((signInMethods) => { // This returns the same array as fetchProvidersForEmail but for email // provider identified by 'password' string, signInMethods would contain 2 // different strings: // 'emailLink' if the user previously signed in with an email/link // 'password' if the user has a password. // A user could have both. if (signInMethods.indexOf( firebase.auth.EmailAuthProvider.EMAIL_PASSWORD_SIGN_IN_METHOD) != -1) { // User can sign in with email/password. } if (signInMethods.indexOf( firebase.auth.EmailAuthProvider.EMAIL_LINK_SIGN_IN_METHOD) != -1) { // User can sign in with email/link. } }) .catch((error) => { // Some error occurred, you can inspect the code: error.code });
Come descritto sopra, email/password e email/link sono considerati la stessa firebase.auth.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 eseguito 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, il modo consigliato per conoscere lo stato di autenticazione del tuo utente è impostare un osservatore sull'oggetto
Auth
. È quindi possibile ottenere le informazioni di base sul profilo dell'utente dall'oggettoUser
. 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
:
Web modular API
import { getAuth, signOut } from "firebase/auth"; const auth = getAuth(); signOut(auth).then(() => { // Sign-out successful. }).catch((error) => { // An error happened. });
Web namespaced API
firebase.auth().signOut().then(() => { // Sign-out successful. }).catch((error) => { // An error happened. });