电话身份验证

通过手机身份验证,用户可以使用手机作为身份验证器来登录 Firebase。系统会向用户发送短信(使用提供的手机号码),其中包含一个唯一代码。代码获得授权后,用户就可以登录 Firebase。

Google 会接收和存储最终用户为完成身份验证而提供的手机号码,以便各种 Google 服务(包括但不限于 Firebase)更好地防范垃圾内容和滥用行为。在使用 Firebase Authentication 手机号码登录服务之前,开发者应确保已征得最终用户的同意。

并非所有国家/地区都支持 Firebase 手机身份验证。如需了解详情,请参阅常见问题解答

设置

在开始使用手机身份验证之前,请确保您已执行以下步骤:

  1. Firebase 控制台中启用手机作为登录方法。
  2. Android:如果您尚未在 Firebase 控制台中设置应用的 SHA-1 哈希,请执行此操作。如需了解如何查找应用的 SHA-1 哈希,请参阅对客户端进行身份验证
  3. iOS:在 Xcode 中为您的项目启用推送通知,并确保您已使用 Firebase Cloud Messaging (FCM) 配置了 APNs 身份验证密钥。此外,您还必须为远程通知启用后台模式。如需查看此步骤的深入说明,请参阅 Firebase iOS 手机身份验证文档。
  4. Web:确保您已在 Firebase 控制台OAuth 重定向网域下添加您的应用网域。

注意:手机号码登录仅适用于真实设备和 Web。如需在设备模拟器上测试您的身份验证流程,请参阅测试

用法

Firebase Authentication SDK for Flutter 提供两种让用户使用手机号码登录的方式。原生(例如 Android 和 iOS)平台提供的手机号码验证功能与 Web 不同,因此每个平台各有其方法:

  • 原生平台verifyPhoneNumber
  • Web 平台signInWithPhoneNumber

原生:verifyPhoneNumber

在原生平台上,用户的手机号码必须先通过验证,然后用户才能通过 PhoneAuthCredential 登录或关联自己的帐号。

首先,您必须提示用户输入手机号码。用户提供手机号码后,调用 verifyPhoneNumber() 方法:

await FirebaseAuth.instance.verifyPhoneNumber(
  phoneNumber: '+44 7123 123 456',
  verificationCompleted: (PhoneAuthCredential credential) {},
  verificationFailed: (FirebaseAuthException e) {},
  codeSent: (String verificationId, int? resendToken) {},
  codeAutoRetrievalTimeout: (String verificationId) {},
);

您必须处理 4 个单独的回调,每个回调都将确定您更新应用界面的方式:

  1. verificationCompleted:自动在 Android 设备上处理短信代码。
  2. verificationFailed:处理失败事件,例如手机号码无效或是否已超出短信配额。
  3. codeSent:在代码从 Firebase 发送到设备后进行处理,用于提示用户输入代码。
  4. codeAutoRetrievalTimeout:处理自动短信代码处理失败时的超时情况。

verificationCompleted

此处理程序只能在支持自动短信代码解析的 Android 设备上调用。

短信代码发送到设备后,Android 会自动验证短信代码,用户无需手动输入代码。如果发生此事件,系统会自动提供 PhoneAuthCredential,它可用于使用用户的手机号码登录或关联用户的手机号码。

FirebaseAuth auth = FirebaseAuth.instance;

await auth.verifyPhoneNumber(
  phoneNumber: '+44 7123 123 456',
  verificationCompleted: (PhoneAuthCredential credential) async {
    // ANDROID ONLY!

    // Sign the user in (or link) with the auto-generated credential
    await auth.signInWithCredential(credential);
  },
);

verificationFailed

如果 Firebase 返回错误(例如,手机号码不正确或超出项目的短信配额),系统会向此处理程序发送 FirebaseAuthException。在这种情况下,您可以根据错误代码提示用户,系统出现了错误。

FirebaseAuth auth = FirebaseAuth.instance;

await auth.verifyPhoneNumber(
  phoneNumber: '+44 7123 123 456',
  verificationFailed: (FirebaseAuthException e) {
    if (e.code == 'invalid-phone-number') {
      print('The provided phone number is not valid.');
    }

    // Handle other errors
  },
);

codeSent

Firebase 向设备发送短信代码时,会使用 verificationIdresendTokenresendToken 仅在 Android 设备上受支持,iOS 设备始终会返回 null 值)触发此处理程序。

触发之后,最好更新您的应用界面,提示用户输入预期的短信代码。用户输入短信代码后,您可以将验证 ID 与短信代码结合使用来创建一个新的 PhoneAuthCredential

FirebaseAuth auth = FirebaseAuth.instance;

await auth.verifyPhoneNumber(
  phoneNumber: '+44 7123 123 456',
  codeSent: (String verificationId, int? resendToken) async {
    // Update the UI - wait for the user to enter the SMS code
    String smsCode = 'xxxx';

    // Create a PhoneAuthCredential with the code
    PhoneAuthCredential credential = PhoneAuthProvider.credential(verificationId: verificationId, smsCode: smsCode);

    // Sign the user in (or link) with the credential
    await auth.signInWithCredential(credential);
  },
);

默认情况下,Firebase 不会重新发送最近发送的短信。不过,您可以使用 forceResendingToken 参数的重新发送令牌重新调用 verifyPhoneNumber 方法来替换此行为。如果成功,短信将会重新发送。

codeAutoRetrievalTimeout

在支持自动短信代码解析的 Android 设备上,如果设备没有在特定时间段内自动解析短信,系统会调用此处理程序。过了该时间段后,设备将不再尝试解析任何收到的消息。

默认情况下,设备会等待 30 秒,但您可以使用 timeout 参数自定义此时长:

FirebaseAuth auth = FirebaseAuth.instance;

await auth.verifyPhoneNumber(
  phoneNumber: '+44 7123 123 456',
  timeout: const Duration(seconds: 60),
  codeAutoRetrievalTimeout: (String verificationId) {
    // Auto-resolution timed out...
  },
);

Web:signInWithPhoneNumber

在 Web 平台上,用户可以通过输入发送到所提供的手机号码的短信代码来确认自己有权使用该手机,从而完成登录过程。为了提高安全性以及防范垃圾内容,系统会要求用户完成 Google reCAPTCHA widget 来证明自己是真人。确认后,系统会发送短信代码。

默认情况下,Firebase Authentication SDK for Flutter 将直接管理 reCAPTCHA widget,但如果需要,您可以控制其显示和配置方式。首先,请使用手机号码调用 signInWithPhoneNumber 方法。

FirebaseAuth auth = FirebaseAuth.instance;

// Wait for the user to complete the reCAPTCHA & for an SMS code to be sent.
ConfirmationResult confirmationResult = await auth.signInWithPhoneNumber('+44 7123 123 456');

调用此方法将首先触发显示 reCAPTCHA widget。用户必须先完成测试,然后系统才会发送短信代码。用户完成测试后,您可以在解析的 ConfirmationResult 响应中向 confirm 方法提供短信代码,以便登录用户:

UserCredential userCredential = await confirmationResult.confirm('123456');

与其他登录流程一样,成功登录会触发整个应用中订阅的任何身份验证状态监听器。

reCAPTCHA 配置

reCAPTCHA widget 是一个全代管式流程,可为您的 Web 应用提供安全保护。

signInWithPhoneNumber 的第二个参数接受可选的 RecaptchaVerifier 实例,该实例可用于管理该 widget。默认情况下,当登录流程被触发时,该 widget 会呈现为不可见的 widget。“不可见的”widget 将以整页模式覆盖应用页面。

不过,您可以显示一个内嵌 widget,用户必须明确点按该 widget 来验证自己。

如需添加内嵌 widget,请为 RecaptchaVerifier 实例的 container 参数指定 DOM 元素 ID。该元素必须存在且为空,否则系统将抛出错误。如果未提供 container 参数,则该 widget 将呈现为“不可见的”widget。

ConfirmationResult confirmationResult = await auth.signInWithPhoneNumber('+44 7123 123 456', RecaptchaVerifier(
  container: 'recaptcha',
  size: RecaptchaVerifierSize.compact,
  theme: RecaptchaVerifierTheme.dark,
));

(可选)您可以通过自定义 sizetheme 参数来更改大小和主题,如上所示。

您还可以监听事件,例如用户是否已完成 reCAPTCHA 、reCAPTCHA 是否已过期或系统是否抛出了错误:

RecaptchaVerifier(
  onSuccess: () => print('reCAPTCHA Completed!'),
  onError: (FirebaseAuthException error) => print(error),
  onExpired: () => print('reCAPTCHA Expired!'),
);

测试

Firebase 支持在本地测试手机号码:

  1. 在 Firebase 控制台上,选择“手机”身份验证提供方,然后点击“Phone numbers for testing”(用于测试的手机号码)下拉菜单。
  2. 输入新的手机号码(例如 +44 7444 555666)和测试代码(例如 123456)。

如果向 verifyPhoneNumbersignInWithPhoneNumber 方法提供测试手机号码,则系统不会真的发送短信。您可以改为直接向 PhoneAuthProvidersignInWithPhoneNumber 确认结果处理程序提供测试代码。