您可以使用 Firebase 驗證功能,傳送含有連結的電子郵件給使用者,讓他們點選連結登入。在這個過程中,使用者的電子郵件地址也會經過驗證。
透過電子郵件登入有許多好處:
- 註冊和登入流程簡便。
- 降低跨應用程式重複使用密碼的風險,這可能會破壞精心挑選的密碼安全性。
- 驗證使用者身分,同時確認使用者是否為電子郵件地址的合法擁有者。
- 使用者只需要具備可存取的電子郵件帳戶即可登入。不必擁有電話號碼或社群媒體帳戶。
- 使用者可以安全登入,無須提供 (或記住) 密碼,這在行動裝置上可能會很麻煩。
- 如果使用者先前是使用電子郵件 ID (密碼或聯合登入) 登入,則可升級為只使用電子郵件登入。舉例來說,如果使用者忘記密碼,仍可登入帳戶,無須重設密碼。
事前準備
設定 Android 專案
如果您尚未將 Firebase 新增至 Android 專案,請新增 Firebase。
在模組 (應用程式層級) Gradle 檔案 (通常為
<project>/<app-module>/build.gradle.kts
或<project>/<app-module>/build.gradle
) 中,加入 Android 的 Firebase Authentication 程式庫依附元件。建議您使用 Firebase Android BoM 來控制程式庫版本。此外,您還需要在設定 Firebase Authentication 時,將 Google Play 服務 SDK 新增至應用程式。
dependencies { // Import the BoM for the Firebase platform implementation(platform("com.google.firebase:firebase-bom:33.7.0")) // 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:21.3.0") }只要使用 Firebase Android BoM,應用程式就會一律使用相容的 Firebase Android 程式庫版本。
(替代做法) 不使用 BoM 新增 Firebase 程式庫依附元件
如果您選擇不使用 Firebase BoM,則必須在依附元件行中指定每個 Firebase 程式庫版本。
請注意,如果您在應用程式中使用多個 Firebase 程式庫,強烈建議您使用 BoM 來管理程式庫版本,確保所有版本皆相容。
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:23.1.0")
// Also add the dependency for the Google Play services library and specify its version implementation("com.google.android.gms:play-services-auth:21.3.0") }
為 Firebase 專案啟用電子郵件連結登入功能
如要透過電子郵件連結登入使用者,您必須先為 Firebase 專案啟用電子郵件提供者和電子郵件連結登入方式:
- 在 Firebase 控制台中,開啟「Auth」部分。
- 在「Sign in method」分頁中,啟用「Email/Password」提供者。請注意,您必須啟用電子郵件/密碼登入功能,才能使用電子郵件連結登入功能。
- 在同一個部分中,啟用「電子郵件連結 (不需要密碼即可登入)」登入方式。
- 按一下 [儲存]。
將驗證連結傳送至使用者的電子郵件地址
如要啟動驗證流程,請向使用者顯示介面,提示使用者提供電子郵件地址,然後呼叫 sendSignInLinkToEmail
,要求 Firebase 將驗證連結傳送至使用者的電子郵件地址。
建構 ActionCodeSettings 物件,為 Firebase 提供如何建構電子郵件連結的指示。設定下列欄位:
url
:要嵌入的深層連結,以及要傳遞的任何其他狀態。連結的網域必須在 Firebase 主控台的授權網域清單中加入許可清單,您可以前往「登入方式」分頁 (「驗證」->「登入方式」) 查看這份清單。如果使用者的裝置上未安裝應用程式,且無法安裝應用程式,連結會將使用者重新導向至這個網址。androidPackageName
和IOSBundleId
:在 Android 或 Apple 裝置上開啟登入連結時要使用的應用程式。進一步瞭解如何設定 Firebase Dynamic Links,透過行動應用程式開啟電子郵件動作連結。handleCodeInApp
:設為 true。與其他非頻道電子郵件操作 (密碼重設和電子郵件驗證) 不同,登入作業必須一律在應用程式中完成。這是因為在流程結束時,使用者應已登入,且其驗證狀態會在應用程式中保留。dynamicLinkDomain
:如果為專案定義多個自訂動態連結網域,請在透過指定行動應用程式 (例如example.page.link
) 開啟連結時,指定要使用的網域。否則,系統會自動選取第一個網域。
Kotlin
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();
如要進一步瞭解 ActionCodeSettings,請參閱「在電子郵件動作中傳遞狀態」一節。
請使用者提供電子郵件地址。
將驗證連結傳送至使用者的電子郵件地址,並儲存使用者的電子郵件地址,以防使用者在同一裝置上完成電子郵件登入程序。
Kotlin
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."); } } });
使用電子郵件連結完成登入
安全疑慮
為了避免有人使用登入連結,以非預期使用者的身分或在非預期的裝置上登入,Firebase Auth 要求使用者在完成登入流程時提供電子郵件地址。如要成功登入,這個電子郵件地址必須與登入連結原本傳送的地址相符。
您可以為在要求連結時使用的裝置上開啟登入連結的使用者,簡化這項流程,方法是在傳送登入電子郵件時,將使用者的電子郵件地址儲存在本機 (例如使用 SharedPreferences)。然後使用這個地址完成流程。請勿在重新導向網址參數中傳遞使用者的電子郵件,並重複使用,因為這可能會啟用工作階段注入。
登入完成後,系統會從使用者移除先前未經驗證的登入機制,並將所有現有工作階段設為無效。舉例來說,如果有人先前使用相同的電子郵件地址和密碼建立未經驗證的帳戶,系統會移除使用者的密碼,以防冒用者聲稱擁有該帳戶,並使用未經驗證的電子郵件地址和密碼再次登入。
此外,請務必在實際工作環境中使用 HTTPS 網址,以免連結遭到中繼伺服器攔截。
在 Android 應用程式中完成登入
Firebase 驗證會使用 Firebase 動態連結,將電子郵件連結傳送至行動裝置。如要透過行動應用程式完成登入程序,應用程式必須經過設定,才能偵測傳入的應用程式連結、剖析底層深層連結,然後完成登入程序。
設定 Firebase Dynamic Links
Firebase Auth 在傳送要在行動應用程式中開啟的連結時,會使用 Firebase Dynamic Links。如要使用這項功能,您必須在 Firebase 控制台中設定動態連結。
啟用 Firebase Dynamic Links:
- 在 Firebase 控制台中,開啟「Dynamic Links」專區。
-
如果您尚未接受 Dynamic Links 條款並建立 Dynamic Links 網域,請立即完成。
如果您已建立 Dynamic Links 網域,請記下該網域。Dynamic Links 網域通常如下所示:
example.page.link
您需要這個值,才能設定 Apple 或 Android 應用程式,以便攔截傳入的連結。
設定 Android 應用程式:
- 為了處理來自 Android 應用程式的這些連結,您必須在 Firebase 控制台專案設定中指定 Android 套件名稱。此外,您也必須提供應用程式憑證的 SHA-1 和 SHA-256。
- 您已新增動態連結網域,並確認 Android 應用程式設定正確無誤,因此動態連結會從啟動器活動開始,重新導向至您的應用程式。
- 如果您希望動態連結重新導向至特定活動,就必須在 AndroidManifest.xml 檔案中設定意圖篩選器。方法是在意圖篩選器中指定動態連結網域或電子郵件動作處理常式。根據預設,電子郵件動作處理常式會託管在以下範例所示的網域上:
PROJECT_ID.firebaseapp.com/
- 注意事項:
- 請勿在意圖篩選器中指定您在 actionCodeSettings 上設定的網址。
- 建立動態連結網域時,您可能也會建立短網址連結。系統不會傳遞這個短網址;請勿設定意圖篩選器,以便透過
android:pathPrefix
屬性擷取短網址。也就是說,您無法在應用程式的不同部分擷取不同的動態連結。不過,您可以檢查連結中的mode
查詢參數,瞭解系統嘗試執行哪些作業,或是使用isSignInWithEmailLink
等 SDK 方法,查看應用程式收到的連結是否符合您的需求。
- 如要進一步瞭解如何接收動態連結,請參閱「接收 Android 動態連結指示」。
驗證連結並登入
收到上述連結後,請確認該連結是用於電子郵件連結驗證,然後完成登入程序。
Kotlin
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()); } } }); }
如要進一步瞭解如何在 Apple 應用程式中使用電子郵件連結登入,請參閱 Apple 平台指南。
如要瞭解如何在網頁應用程式中處理透過電子郵件連結登入的作業,請參閱網頁指南。
使用電子郵件連結連結/重新驗證
您也可以將這種驗證方法連結至現有使用者。舉例來說,如果使用者先前透過其他提供者 (例如電話號碼) 進行驗證,便可將這類登入方式新增至現有帳戶。
差異在於作業的後半段:
Kotlin
// 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()); } } });
您也可以在執行敏感作業前,重新驗證電子郵件連結使用者。
Kotlin
// 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()); } } });
不過,由於流程可能會在未登入原始使用者帳戶的不同裝置上結束,因此可能無法完成這項流程。在這種情況下,您可以向使用者顯示錯誤訊息,強制他們在同一裝置上開啟連結。部分狀態可透過連結傳遞,提供操作類型和使用者 UID 的相關資訊。
已淘汰:區分電子郵件密碼和電子郵件連結
如果您是在 2023 年 9 月 15 日當天或之後建立專案,系統會預設啟用電子郵件列舉保護功能。這項功能可提升專案使用者帳戶的安全性,但會停用 fetchSignInMethodsForEmail()
方法,我們先前曾建議使用這項方法實作 ID 優先流程。
雖然您可以為專案停用電子郵件列舉防護,但我們不建議這麼做。
詳情請參閱電子郵件列舉防護功能的說明文件。
後續步驟
使用者首次登入後,系統會建立新使用者帳戶,並連結至使用者登入時所用的憑證 (即使用者名稱和密碼、電話號碼或驗證服務提供者資訊)。這個新帳戶會儲存在 Firebase 專案中,無論使用者如何登入,都可以用於在專案中的每個應用程式中識別使用者。
-
在應用程式中,您可以從
FirebaseUser
物件取得使用者的個人資料基本資訊。請參閱「 管理使用者」。 在 Firebase Realtime Database 和 Cloud Storage 安全性規則中,您可以從
auth
變數取得已登入使用者的專屬使用者 ID,並利用該 ID 控管使用者可存取的資料。
您可以將驗證服務供應商憑證連結至現有使用者帳戶,讓使用者使用多個驗證服務供應商登入應用程式。
如要將使用者登出,請呼叫
signOut
:
Kotlin
Firebase.auth.signOut()
Java
FirebaseAuth.getInstance().signOut();