在 Apple 平台上使用電子郵件連結向 Firebase 驗證

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

透過電子郵件登入有許多好處:

  • 註冊和登入流程簡便。
  • 降低跨應用程式重複使用密碼的風險,這可能會破壞精心挑選的密碼安全性。
  • 驗證使用者身分,同時確認使用者是否為電子郵件地址的合法擁有者。
  • 使用者只需要具備可存取的電子郵件帳戶即可登入。不必擁有電話號碼或社群媒體帳戶。
  • 使用者可以安全地登入,而無須提供 (或記住) 密碼,這在行動裝置上可能會很麻煩。
  • 如果使用者先前是使用電子郵件 ID (密碼或聯合登入) 登入,則可升級為只使用電子郵件登入。舉例來說,如果使用者忘記密碼,仍可登入帳戶,無須重設密碼。

事前準備

使用 Swift Package Manager 安裝及管理 Firebase 依附元件。

  1. 在 Xcode 中保持開啟應用程式專案,然後依序點選「File」(檔案) 和「Add Packages」(新增 Package)
  2. 系統提示時,請新增 Firebase Apple 平台 SDK 存放區:
  3.   https://github.com/firebase/firebase-ios-sdk.git
  4. 選擇 Firebase Authentication 程式庫。
  5. -ObjC 標記新增至目標的建構設定「Other Linker Flags」部分。
  6. 完成後,Xcode 就會自動開始在背景中解析並下載依附元件。

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

  1. Firebase 控制台中,開啟「Auth」部分。
  2. 在「Sign in method」分頁中,啟用「Email/Password」提供者。請注意,您必須啟用電子郵件/密碼登入功能,才能使用電子郵件連結登入功能。
  3. 在同一個部分中,啟用「電子郵件連結 (不需要密碼即可登入)」登入方式。
  4. 按一下 [儲存]

如要啟動驗證流程,請向使用者顯示介面,提示使用者提供電子郵件地址,然後呼叫 sendSignInLink,要求 Firebase 將驗證連結傳送至使用者的電子郵件地址。

  1. 建構 ActionCodeSettings 物件,為 Firebase 提供如何建構電子郵件連結的指示。設定下列欄位:

    • url:要嵌入的深層連結,以及要傳遞的任何其他狀態。連結的網域必須在 Firebase 主控台的授權網域清單中加入許可清單,您可以前往「登入方式」分頁 (「驗證」->「登入方式」) 查看這份清單。
    • iOSBundleIDandroidPackageName:協助 Firebase Authentication 判斷是否應建立在 Android 或 Apple 裝置上開啟的僅限網頁或行動連結。
    • handleCodeInApp:設為 true。與其他非頻道電子郵件操作 (密碼重設和電子郵件驗證) 不同,登入作業必須一律在應用程式中完成。這是因為在流程結束時,使用者應已登入,且其驗證狀態會在應用程式中保留。
    • linkDomain:為專案定義自訂 Hosting 連結網域時,請指定在特定行動應用程式開啟連結時要使用的網域。否則系統會自動選取預設網域 (例如 PROJECT_ID.firebaseapp.com)。
    • dynamicLinkDomain:已淘汰。請勿指定此參數。

    Swift

    let actionCodeSettings = ActionCodeSettings()
    actionCodeSettings.url = URL(string: "https://www.example.com")
    // The sign-in operation has to always be completed in the app.
    actionCodeSettings.handleCodeInApp = true
    actionCodeSettings.setIOSBundleID(Bundle.main.bundleIdentifier!)
    actionCodeSettings.setAndroidPackageName("com.example.android",
                                             installIfNotAvailable: false, minimumVersion: "12")

    Objective-C

    FIRActionCodeSettings *actionCodeSettings = [[FIRActionCodeSettings alloc] init];
    [actionCodeSettings setURL:[NSURL URLWithString:@"https://www.example.com"]];
    // The sign-in operation has to always be completed in the app.
    actionCodeSettings.handleCodeInApp = YES;
    [actionCodeSettings setIOSBundleID:[[NSBundle mainBundle] bundleIdentifier]];
    [actionCodeSettings setAndroidPackageName:@"com.example.android"
                        installIfNotAvailable:NO
                               minimumVersion:@"12"];

    如要進一步瞭解 ActionCodeSettings,請參閱「在電子郵件動作中傳遞狀態」一節。

  2. 請使用者提供電子郵件地址。

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

    Swift

    Auth.auth().sendSignInLink(toEmail: email,
                               actionCodeSettings: actionCodeSettings) { error in
      // ...
        if let error = error {
          self.showMessagePrompt(error.localizedDescription)
          return
        }
        // 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.
        UserDefaults.standard.set(email, forKey: "Email")
        self.showMessagePrompt("Check your email for link")
        // ...
    }

    Objective-C

    [[FIRAuth auth] sendSignInLinkToEmail:email
                       actionCodeSettings:actionCodeSettings
                               completion:^(NSError *_Nullable error) {
      // ...
        if (error) {
          [self showMessagePrompt:error.localizedDescription];
           return;
        }
        // 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.
        [NSUserDefaults.standardUserDefaults setObject:email forKey:@"Email"];
        [self showMessagePrompt:@"Check your email for link"];
        // ...
    }];

安全疑慮

為了避免有人使用登入連結,以非預期使用者的身分或在非預期的裝置上登入,Firebase Auth 要求使用者在完成登入流程時提供電子郵件地址。如要順利登入,這個電子郵件地址必須與登入連結原先傳送的地址相符。

您可以為在要求連結時使用的裝置上開啟登入連結的使用者,在傳送登入電子郵件時將電子郵件地址儲存在本機,藉此簡化這項流程。然後使用這個地址完成流程。

登入完成後,系統會從使用者移除先前未經過驗證的登入機制,並將所有現有工作階段設為無效。舉例來說,如果有人先前使用相同的電子郵件地址和密碼建立未經驗證的帳戶,系統會移除該使用者的密碼,以免冒用者聲稱擁有該帳戶,並使用該未經驗證的帳戶再次登入。

在 Apple 行動應用程式中完成登入

Firebase Authentication 會使用 Firebase Hosting 將電子郵件連結傳送至行動裝置。如要透過行動應用程式完成登入程序,應用程式必須經過設定,才能偵測傳入的應用程式連結、剖析底層深層連結,然後完成登入程序。如要進一步瞭解如何完成這項操作,請參閱iOS 通用連結和相關網域

設定「Firebase Hosting

Firebase Authentication 在建立及傳送要在行動應用程式中開啟的連結時,會使用 Firebase Hosting 網域。我們已為您設定預設的 Firebase Hosting 網域。

  1. 設定 Firebase Hosting 網域:

    Firebase 控制台中,開啟「Hosting」部分。

    • 如果您想使用預設網域,讓在行動應用程式中開啟的電子郵件連結,請前往預設網站,並記下預設 Hosting 網域。預設的 Hosting 網域通常會像這樣:PROJECT_ID.firebaseapp.com

      您需要這個值,才能設定應用程式來攔截傳入的連結。

    • 如果您想為電子郵件連結使用自訂網域,可以透過 Firebase Hosting 註冊一個網域,並將該網域用於連結。

  2. 設定 Apple 應用程式:

    您需要將所選網域設為應用程式連結的相關網域。如要在應用程式中設定授權,請在 Xcode 中開啟目標的「Signing & Capabilities」分頁,然後將上一個步驟中的 Firebase 代管服務網域新增至「Associated Domains」功能。如果使用預設的 Firebase Hosting 網域,則會是 applinks:PROJECT_ID.firebaseapp.com

    詳情請參閱 Apple 說明文件網站上的「支援相關網域」。

收到上述連結後,請確認該連結是用於電子郵件連結驗證,然後完成登入程序。

Swift

if Auth.auth().isSignIn(withEmailLink: link) {
        Auth.auth().signIn(withEmail: email, link: self.link) { user, error in
          // ...
        }
}

Objective-C

if ([[FIRAuth auth] isSignInWithEmailLink:link]) {
    [[FIRAuth auth] signInWithEmail:email
                               link:link
                         completion:^(FIRAuthDataResult * _Nullable authResult, NSError * _Nullable error) {
      // ...
    }];
}

如要瞭解如何在 Android 應用程式中處理透過電子郵件連結登入的作業,請參閱 Android 指南

如要瞭解如何在網頁應用程式中處理透過電子郵件連結登入的作業,請參閱網頁指南

您也可以將這種驗證方法連結至現有使用者。舉例來說,如果使用者先前透過其他提供者 (例如電話號碼) 進行驗證,便可將這類登入方式新增至現有帳戶。

差異在於運算的後半部:

Swift

  let credential = EmailAuthCredential.credential(withEmail:email
                                                       link:link)
  Auth.auth().currentUser?.link(with: credential) { authData, error in
    if (error) {
      // And error occurred during linking.
      return
    }
    // The provider was successfully linked.
    // The phone user can now sign in with their phone number or email.
  }

Objective-C

  FIRAuthCredential *credential =
      [FIREmailAuthProvider credentialWithEmail:email link:link];
  [FIRAuth auth].currentUser
      linkWithCredential:credential
              completion:^(FIRAuthDataResult *_Nullable result,
                           NSError *_Nullable error) {
    if (error) {
      // And error occurred during linking.
      return;
    }
    // The provider was successfully linked.
    // The phone user can now sign in with their phone number or email.
  }];

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

Swift

  let credential = EmailAuthProvider.credential(withEmail:email
                                                       link:link)
  Auth.auth().currentUser?.reauthenticate(with: credential) { authData, error in
    if (error) {
      // And error occurred during re-authentication.
      return
    }
    // The user was successfully re-authenticated.
  }

Objective-C

  FIRAuthCredential *credential =
      [FIREmailAuthCredential credentialWithEmail:email link:link];
  [FIRAuth auth].currentUser
      reauthenticateWithCredential:credential
                        completion:^(FIRAuthDataResult *_Nullable result,
                                     NSError *_Nullable error) {
    if (error) {
      // And error occurred during re-authentication
      return;
    }
    // The user was successfully re-authenticated.
  }];

不過,由於流程可能會在未登入原始使用者帳戶的不同裝置上結束,因此可能無法完成這項流程。在這種情況下,您可以向使用者顯示錯誤訊息,強制他們在同一裝置上開啟連結。部分狀態可透過連結傳遞,提供作業類型和使用者 UID 的相關資訊。

Firebase Authentication iOS SDK 11.8.0 版之前,電子郵件連結登入功能會使用 Firebase Dynamic Links 在正確的應用程式中開啟登入連結。由於 Firebase Dynamic Links 將在 2025 年 8 月 25 日停用,因此這些驗證連結已淘汰。

如果您的應用程式使用舊版連結,應遷移應用程式至新的 Firebase Hosting 系統。

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

雖然您可以為專案停用電子郵件列舉防護,但我們不建議這麼做。

詳情請參閱「啟用或停用電子郵件列舉保護功能」。

後續步驟

使用者首次登入後,系統會建立新使用者帳戶,並連結至使用者登入時所用的憑證 (即使用者名稱和密碼、電話號碼或驗證服務提供者資訊)。這個新帳戶會儲存在 Firebase 專案中,無論使用者如何登入,都可以用於在專案中的每個應用程式中識別使用者。

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

  • Firebase Realtime DatabaseCloud Storage 安全性規則中,您可以從 auth 變數取得已登入使用者的專屬使用者 ID,並利用該 ID 控管使用者可存取的資料。

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

如要讓使用者登出,請呼叫 signOut:

Swift

let firebaseAuth = Auth.auth()
do {
  try firebaseAuth.signOut()
} catch let signOutError as NSError {
  print("Error signing out: %@", signOutError)
}

Objective-C

NSError *signOutError;
BOOL status = [[FIRAuth auth] signOut:&signOutError];
if (!status) {
  NSLog(@"Error signing out: %@", signOutError);
  return;
}

您可能還想為各種驗證錯誤新增錯誤處理程式碼。請參閱「處理錯誤」。