获取我们在 Firebase 峰会上发布的所有信息,了解 Firebase 可如何帮助您加快应用开发速度并满怀信心地运行应用。了解详情

在 Apple 平台上使用电子邮件链接通过 Firebase 进行身份验证

您可以使用 Firebase 身份验证通过向用户发送包含链接的电子邮件来登录用户,他们可以单击该链接进行登录。在此过程中,还会验证用户的电子邮件地址。

通过电子邮件登录有很多好处:

  • 低摩擦注册和登录。
  • 降低跨应用程序重复使用密码的风险,这可能会破坏即使是精心挑选的密码的安全性。
  • 能够验证用户身份,同时验证用户是否是电子邮件地址的合法所有者。
  • 用户只需要一个可访问的电子邮件帐户即可登录。不需要拥有电话号码或社交媒体帐户。
  • 用户无需提供(或记住)密码即可安全登录,这在移动设备上可能很麻烦。
  • 以前使用电子邮件标识符(密码或联合身份)登录的现有用户可以升级为仅使用电子邮件登录。例如,忘记密码的用户仍然可以登录而无需重置密码。

在你开始之前

使用 Swift Package Manager 安装和管理 Firebase 依赖项。

  1. 在 Xcode 中,打开您的应用项目,导航到File > Add Packages
  2. 出现提示时,添加 Firebase Apple 平台 SDK 存储库:
  3.   https://github.com/firebase/firebase-ios-sdk
  4. 选择 Firebase 身份验证库。
  5. 完成后,Xcode 将在后台自动开始解析和下载您的依赖项。

要通过电子邮件链接登录用户,您必须首先为您的 Firebase 项目启用电子邮件提供商和电子邮件链接登录方法:

  1. Firebase 控制台中,打开Auth部分。
  2. 登录方法选项卡上,启用电子邮件/密码提供程序。请注意,必须启用电子邮件/密码登录才能使用电子邮件链接登录。
  3. 在同一部分中,启用电子邮件链接(无密码登录)登录方法。
  4. 单击保存

要启动身份验证流程,请向用户显示一个界面,提示用户提供他们的电子邮件地址,然后调用sendSignInLinkToEmail:actionCodeSettings:completion:以请求 Firebase 将身份验证链接发送到用户的电子邮件。

  1. 构造ActionCodeSettings对象,该对象为 Firebase 提供有关如何构造电子邮件链接的说明。设置以下字段:

    • url:要嵌入的深层链接和要传递的任何其他状态。链接的域必须在授权域的 Firebase 控制台列表中列入白名单,可以通过转到登录方法选项卡(身份验证 -> 登录方法)找到该列表。
    • iOSBundleID 和 androidPackageName :在 Android 或 Apple 设备上打开登录链接时使用的应用程序。详细了解如何配置 Firebase 动态链接以通过移动应用打开电子邮件操作链接。
    • handleCodeInApp:设置为真。与其他带外电子邮件操作(密码重置和电子邮件验证)不同,登录操作必须始终在应用程序中完成。这是因为,在流程结束时,预计用户会登录,并且他们的身份验证状态会保留在应用程序中。
    • dynamicLinkDomain:当为一个项目定义了多个自定义动态链接域时,指定在通过指定的移动应用程序(例如example.page.link )打开链接时使用哪一个。否则将自动选择第一个域。

    迅速

    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. 将认证链接发送到用户邮箱,并保存用户邮箱,以防用户在同一设备上完成邮箱登录。

    迅速

    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 身份验证要求在完成登录流程时提供用户的电子邮件地址。要成功登录,此电子邮件地址必须与最初发送登录链接的地址相匹配。

您可以为在请求链接的同一设备上打开登录链接的用户简化此流程,方法是在您发送登录电子邮件时将他们的电子邮件地址存储在本地。然后,使用此地址完成流程。

登录完成后,任何以前未经验证的登录机制都将从用户中删除,任何现有会话都将失效。例如,如果有人之前使用相同的电子邮件和密码创建了一个未经验证的帐户,则该用户的密码将被删除,以防止声称拥有所有权并创建该未经验证的帐户的冒充者使用相同的帐户再次登录。

在 Apple 移动应用程序中完成登录

Firebase 身份验证使用 Firebase 动态链接将电子邮件链接发送到移动设备。对于通过移动应用程序完成登录,必须将应用程序配置为检测传入的应用程序链接,解析底层深层链接,然后完成登录。

Firebase Auth 在发送要在移动应用程序中打开的链接时使用Firebase 动态链接。要使用此功能,需要在 Firebase 控制台中配置动态链接。

  1. 启用 Firebase 动态链接:

    1. Firebase 控制台中,打开动态链接部分。
    2. 如果您尚未接受动态链接条款并创建动态链接域,请立即执行。

      如果您已经创建了动态链接域,请记下它。动态链接域通常类似于以下示例:

      example.page.link

      当您配置 Apple 或 Android 应用程序以拦截传入链接时,您将需要此值。

  2. 配置 Apple 应用程序:

    1. 如果您计划从您的应用程序中处理这些链接,则需要在 Firebase 控制台项目设置中指定捆绑 ID。此外,App Store ID 和 Apple Developer Team ID 也需要指定。
    2. 您还需要将电子邮件操作处理程序域配置为应用程序功能中的关联域。默认情况下,电子邮件操作处理程序托管在类似于以下示例的域中:
      APP_ID.firebaseapp.com
    3. 如果您计划将应用程序分发到 iOS 8 及以下版本,则需要将您的捆绑 ID 设置为传入 URL 的自定义方案。
    4. 有关这方面的更多信息,请参阅接收 Apple 平台动态链接说明

收到如上所述的链接后,验证它是否用于电子邮件链接身份验证并完成登录。

迅速

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 指南

要了解如何在 Web 应用程序中使用电子邮件链接处理登录,请参阅Web 指南

您还可以将此身份验证方法链接到现有用户。例如,以前通过另一个提供商(例如电话号码)进行身份验证的用户可以将此登录方法添加到他们现有的帐户中。

不同之处在于操作的后半部分:

迅速

  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.
  }];

这也可用于在运行敏感操作之前重新验证电子邮件链接用户。

迅速

  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 的信息。

如果您同时支持密码登录和基于链接的电子邮件登录,为了区分密码/链接用户的登录方法,请使用fetchSignInMethodsForEmail 。这对于首先要求用户提供其电子邮件然后向其显示登录方法的标识符优先流程很有用:

迅速

 // After asking the user for their email.
 Auth.auth().fetchSignInMethods(forEmail: email) { signInMethods, error in
   // This returns the same array as fetchProviders(forEmail:completion:) 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 (error) {
     // Handle error case.
   }
   if (!signInMethods.contains(EmailPasswordAuthSignInMethod)) {
     // User can sign in with email/password.
   }
   if (!signInMethods.contains(EmailLinkAuthSignInMethod)) {
     // User can sign in with email/link.
   }
 }

Objective-C

 // After asking the user for their email.
 [FIRAuth auth] fetchSignInMethodsForEmail:email
                                completion:^(NSArray *_Nullable signInMethods,
                                             NSError *_Nullable error) {
   // 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 (error) {
     // Handle error case.
   }
   if (![signInMethods containsObject:FIREmailPasswordAuthSignInMethod]) {
     // User can sign in with email/password.
   }
   if (![signInMethods containsObject:FIREmailLinkAuthSignInMethod]) {
     // User can sign in with email/link.
   }
 }];

如上所述,电子邮件/密码和电子邮件/链接被视为具有不同登录方法的相同FIREmailAuthProvider (相同PROVIDER_ID )。

下一步

用户首次登录后,会创建一个新用户帐户并将其链接到凭据(即用户名和密码、电话号码或身份验证提供商信息),即用户登录时使用的凭据。这个新帐户作为 Firebase 项目的一部分存储,可用于在项目中的每个应用中识别用户,无论用户如何登录。

  • 在您的应用程序中,您可以从FIRUser对象获取用户的基本个人资料信息。请参阅管理用户

  • 在您的 Firebase 实时数据库和云存储安全规则中,您可以从auth变量中获取登录用户的唯一用户 ID,并使用它来控制用户可以访问哪些数据。

您可以通过将身份验证提供程序凭据链接到现有用户帐户来允许用户使用多个身份验证提供程序登录您的应用程序。

要注销用户,请调用signOut:

迅速

    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;
}

您可能还想为所有身份验证错误添加错误处理代码。请参阅处理错误