使用電子郵件連結向 Firebase 驗證

您可以使用 Firebase 驗證功能,向使用者傳送含有連結的電子郵件,讓他們點選即可登入。在過程中,系統也會驗證使用者的電子郵件地址。

使用電子郵件登入有以下優點:

  • 簡化註冊和登入程序。
  • 降低應用程式之間重複使用密碼的風險,可能導致選取的密碼安全性不佳。
  • 驗證使用者身分,同時驗證使用者是否為電子郵件地址的合法擁有者。
  • 使用者只需具備可存取的電子郵件帳戶即可登入。不需要具備電話號碼或社群媒體帳戶的擁有權。
  • 使用者不需提供 (或記住) 密碼,即可安全登入,這對行動裝置來說可能很麻煩。
  • 先前以電子郵件 ID (密碼或聯合) 登入的現有使用者之升級,可以升級到僅使用電子郵件登入。舉例來說,如果使用者忘記密碼,仍然可以在不需要重設密碼的情況下登入。

事前準備

  1. 如果您尚未安裝,請按照入門指南中的步驟操作。

  2. 為 Firebase 專案啟用電子郵件連結登入功能。

    如要透過電子郵件連結登入使用者,您必須先為 Firebase 專案啟用電子郵件服務供應商和電子郵件連結登入方式:

    1. Firebase 控制台開啟「驗證」專區。
    2. 在「Sign in method」分頁中,啟用「Email/Password」供應商。 請注意,您必須啟用電子郵件/密碼登入功能,才能使用電子郵件連結登入。
    3. 在相同區段中,啟用「Email link (無密碼登入)」登入方式。
    4. 按一下「儲存」

如要啟動驗證流程,系統會顯示一個介面,提示使用者提供自己的電子郵件地址,然後呼叫 sendSignInLinkToEmail() 以要求 Firebase 將驗證連結傳送至使用者的電子郵件。

  1. 建構 ActionCodeSettings 物件,藉此向 Firebase 提供建構電子郵件連結的操作說明。設定下列欄位:

    • url:要嵌入的深層連結,以及要一併傳遞的任何其他狀態。連結的網域必須在 Firebase 控制台的授權網域清單中加入許可清單,只要前往「登入方式」分頁 (依序點選「驗證」->「登入方式」),就能找到清單。如果使用者的裝置未安裝應用程式,且無法安裝應用程式,這個連結會將使用者重新導向至此網址。

    • androidPackageNameIOSBundleId:在 Android 或 iOS 裝置上開啟登入連結時使用的應用程式。進一步瞭解如何設定 Firebase Dynamic Links,透過行動應用程式開啟電子郵件動作連結。

    • handleCodeInApp:設為 true。登入操作必須一律在應用程式中完成 (密碼重設和電子郵件驗證)。這是因為在流程結束時,使用者會處於登入狀態,驗證狀態也會保留在應用程式中。

    • dynamicLinkDomain:為專案定義多個自訂動態連結網域時,請指定當使用者透過指定的行動應用程式 (例如 example.page.link) 開啟連結時,要使用的網域;否則,系統會自動選取第一個網域。

    var acs = 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,
        iOSBundleId: 'com.example.ios',
        androidPackageName: 'com.example.android',
        // installIfNotAvailable
        androidInstallApp: true,
        // minimumVersion
        androidMinimumVersion: '12');
    
  2. 要求使用者提供電子郵件地址。

  3. 傳送驗證連結至使用者的電子郵件,並儲存使用者的電子郵件地址,以便在使用者在同一部裝置上完成電子郵件地址登入程序。

    var emailAuth = 'someemail@domain.com';
    FirebaseAuth.instance.sendSignInLinkToEmail(
            email: emailAuth, actionCodeSettings: acs)
        .catchError((onError) => print('Error sending email verification $onError'))
        .then((value) => print('Successfully sent email verification'));
    });
    

安全疑慮

為了避免使用者以非預期使用者身分或非預期裝置登入登入連結,Firebase 驗證要求在完成登入流程時必須提供使用者的電子郵件地址。這個電子郵件地址必須與最初的登入連結寄送地址相符,才能成功登入。

當使用者在要求連結的裝置上開啟登入連結時,您可以簡化這項程序,例如將電子郵件地址儲存在本機 (例如在您傳送登入電子郵件時使用 SharedPreferences)。接著,請使用這個地址完成流程。請勿在重新導向網址參數中傳遞使用者的電子郵件,然後重新使用,因為這可能會啟用工作階段插入功能。

登入完成後,所有先前未經驗證的登入機制都會從使用者中移除,且所有現有工作階段都將失效。例如,如果某人之前已使用相同電子郵件地址和密碼建立未經驗證的帳戶,系統會移除使用者的密碼,以防冒用擁有權的冒用者建立了未驗證的帳戶,而在建立未經驗證的帳戶時,無法再使用未經驗證的電子郵件和密碼重新登入。

此外,請務必在實際工作環境中使用 HTTPS 網址,避免中介伺服器攔截您的連結。

Firebase 驗證會使用 Firebase Dynamic Links,將電子郵件連結傳送至行動裝置。如要透過行動應用程式完成登入程序,您必須將應用程式設為偵測收到的應用程式連結,接著剖析基礎深層連結,然後完成登入程序。

  1. 請參閱指南設定應用程式,以便接收 Flutter 上的 Dynamic Links。

  2. 在您的連結處理常式中,檢查連結是否用於電子郵件連結驗證,如果有,請完成登入程序。

    // Confirm the link is a sign-in with email link.
    if (FirebaseAuth.instance.isSignInWithEmailLink(emailLink)) {
      try {
        // The client SDK will parse the code from the link for you.
        final userCredential = await FirebaseAuth.instance
            .signInWithEmailLink(email: emailAuth, emailLink: emailLink);
    
        // You can access the new user via userCredential.user.
        final emailAddress = userCredential.user?.email;
    
        print('Successfully signed in with email link!');
      } catch (error) {
        print('Error signing in with email link.');
      }
    }
    

您也可以將這種驗證方法連結至現有的使用者。舉例來說,使用者先前已透過其他供應商 (例如電話號碼) 完成驗證,就能將這個登入方式新增至現有的帳戶。

差異如下:作業的後半部:

final authCredential = EmailAuthProvider
    .credentialWithLink(email: emailAuth, emailLink: emailLink.toString());
try {
    await FirebaseAuth.instance.currentUser
        ?.linkWithCredential(authCredential);
} catch (error) {
    print("Error linking emailLink credential.");
}

這也可用來在執行敏感作業前,重新驗證電子郵件連結使用者。

final authCredential = EmailAuthProvider
    .credentialWithLink(email: emailAuth, emailLink: emailLink.toString());
try {
    await FirebaseAuth.instance.currentUser
        ?.reauthenticateWithCredential(authCredential);
} catch (error) {
    print("Error reauthenticating credential.");
}

不過,由於流程最終可能會在其他使用者未登入的另一部裝置上,因此可能無法完成這個流程。在這種情況下,系統可能會向使用者顯示錯誤訊息,強制使用者在同一部裝置上開啟連結。有些狀態可在連結中傳遞,提供關於作業類型和使用者 uid 的資訊。

如果專案在 2023 年 9 月 15 日當天或之後建立,系統預設會啟用電子郵件列舉防護功能。這項功能可改善專案使用者帳戶的安全性,但會停用 fetchSignInMethodsForEmail() 方法 (先前建議用於實作 ID 優先流程)。

雖然您可以停用專案的電子郵件列舉防護功能,但建議您不要這麼做。

詳情請參閱電子郵件列舉防護功能說明文件。

後續步驟

使用者建立新帳戶後,這個帳戶會儲存在您的 Firebase 專案中,而且無論使用者採用哪種登入方式,都能在專案中的每個應用程式中識別使用者。

在應用程式中,您可以從 User 物件取得使用者的基本個人資料。請參閱管理使用者

在 Firebase 即時資料庫和 Cloud Storage 安全性規則中,您可以透過 auth 變數取得登入使用者的專屬 ID,並使用該 ID 控制使用者可以存取哪些資料。

您可以將驗證供應商憑證連結到現有的使用者帳戶,讓使用者透過多個驗證供應商登入您的應用程式。

如要將使用者登出,請呼叫 signOut()

await FirebaseAuth.instance.signOut();