Google 致力于为黑人社区推动种族平等。查看具体举措

使用 JavaScript 通过带有电话号码的 Firebase 进行身份验证

使用集合让一切井井有条 根据您的偏好保存内容并对其进行分类。

您可以使用 Firebase 身份验证通过向用户手机发送 SMS 消息来登录用户。用户使用 SMS 消息中包含的一次性代码登录。

将电话号码登录添加到您的应用程序的最简单方法是使用FirebaseUI ,它包括一个插入式登录小部件,用于实现电话号码登录以及基于密码和联合登录的登录流程-在。本文档介绍如何使用 Firebase SDK 实现电话号码登录流程。

在你开始之前

如果您尚未将初始化代码段从Firebase 控制台复制到您的项目中,请按照将Firebase 添加到 JavaScript 项目中的说明进行操作。

安全问题

仅使用电话号码的身份验证虽然方便,但不如其他可用方法安全,因为电话号码的拥有可以在用户之间轻松转移。此外,在具有多个用户配置文件的设备上,任何可以接收 SMS 消息的用户都可以使用设备的电话号码登录帐户。

如果您在应用程序中使用基于电话号码的登录,则应将其与更安全的登录方法一起提供,并告知用户使用电话号码登录的安全权衡。

为您的 Firebase 项目启用电话号码登录

要通过短信登录用户,您必须首先为您的 Firebase 项目启用电话号码登录方法:

  1. Firebase 控制台中,打开身份验证部分。
  2. 登录方式页面,启用电话号码登录方式。
  3. 在同一页面上,如果将托管您的应用程序的域未列在OAuth 重定向域部分中,请添加您的域。

Firebase 的电话号码登录请求配额足够高,大多数应用不会受到影响。但是,如果您需要使用电话身份验证登录大量用户,则可能需要升级您的定价计划。请参阅定价页面。

设置 reCAPTCHA 验证器

您必须先设置 Firebase 的 reCAPTCHA 验证程序,然后才能使用他们的电话号码登录用户。 Firebase 使用 reCAPTCHA 来防止滥用,例如确保电话号码验证请求来自您的应用允许的域之一。

您无需手动设置 reCAPTCHA 客户端;当您使用 Firebase SDK 的RecaptchaVerifier对象时,Firebase 会自动创建和处理任何必要的客户端密钥和机密。

RecaptchaVerifier对象支持不可见的 reCAPTCHA ,它通常可以在不需要任何用户操作的情况下验证用户,以及 reCAPTCHA 小部件,它总是需要用户交互才能成功完成。

通过在呈现 reCAPTCHA 之前更新 Auth 实例上的语言代码,可以将底层呈现的 reCAPTCHA 本地化为用户的偏好。上述本地化也适用于发送给用户的包含验证码的 SMS 消息。

Web version 9

import { getAuth } from "firebase/auth";

const auth = getAuth();
auth.languageCode = 'it';
// To apply the default browser preference instead of explicitly setting it.
// firebase.auth().useDeviceLanguage();

Web version 8

firebase.auth().languageCode = 'it';
// To apply the default browser preference instead of explicitly setting it.
// firebase.auth().useDeviceLanguage();

使用不可见的 reCAPTCHA

要使用不可见的 reCAPTCHA,请创建一个RecaptchaVerifier对象,并将size参数设置为invisible ,并指定提交登录表单的按钮的 ID。例如:

Web version 9

import { getAuth, RecaptchaVerifier } from "firebase/auth";

const auth = getAuth();
window.recaptchaVerifier = new RecaptchaVerifier('sign-in-button', {
  'size': 'invisible',
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    onSignInSubmit();
  }
}, auth);

Web version 8

window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('sign-in-button', {
  'size': 'invisible',
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    onSignInSubmit();
  }
});

使用 reCAPTCHA 小部件

要使用可见的 reCAPTCHA 小部件,请在您的页面上创建一个元素以包含该小部件,然后创建一个RecaptchaVerifier对象,并在您这样做时指定容器的 ID。例如:

Web version 9

import { getAuth, RecaptchaVerifier } from "firebase/auth";

const auth = getAuth();
window.recaptchaVerifier = new RecaptchaVerifier('recaptcha-container', {}, auth);

Web version 8

window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container');

可选:指定 reCAPTCHA 参数

您可以选择在RecaptchaVerifier对象上设置回调函数,当用户解决 reCAPTCHA 或 reCAPTCHA 在用户提交表单之前过期时调用:

Web version 9

import { getAuth, RecaptchaVerifier } from "firebase/auth";

const auth = getAuth();
window.recaptchaVerifier = new RecaptchaVerifier('recaptcha-container', {
  'size': 'normal',
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    // ...
  },
  'expired-callback': () => {
    // Response expired. Ask user to solve reCAPTCHA again.
    // ...
  }
}, auth);

Web version 8

window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container', {
  'size': 'normal',
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    // ...
  },
  'expired-callback': () => {
    // Response expired. Ask user to solve reCAPTCHA again.
    // ...
  }
});

可选:预渲染 reCAPTCHA

如果您想在提交登录请求之前预渲染 reCAPTCHA,请调用render

Web version 9

recaptchaVerifier.render().then((widgetId) => {
  window.recaptchaWidgetId = widgetId;
});

Web version 8

recaptchaVerifier.render().then((widgetId) => {
  window.recaptchaWidgetId = widgetId;
});

render解析后,您将获得 reCAPTCHA 的小部件 ID,您可以使用它来调用reCAPTCHA API:

Web version 9

const recaptchaResponse = grecaptcha.getResponse(recaptchaWidgetId);

Web version 8

const recaptchaResponse = grecaptcha.getResponse(recaptchaWidgetId);

向用户手机发送验证码

要启动电话号码登录,请向用户显示一个界面,提示他们提供电话号码,然后调用signInWithPhoneNumber请求 Firebase 通过 SMS 向用户的手机发送验证码:

  1. 获取用户的电话号码。

    法律要求各不相同,但作为最佳实践并为您的用户设定期望,您应该告知他们,如果他们使用电话登录,他们可能会收到一条短信进行验证,并适用标准费率。

  2. 调用signInWithPhoneNumber ,将用户的电话号码和您之前创建的RecaptchaVerifier传递给它。

    Web version 9

    import { getAuth, signInWithPhoneNumber } from "firebase/auth";
    
    const phoneNumber = getPhoneNumberFromUserInput();
    const appVerifier = window.recaptchaVerifier;
    
    const auth = getAuth();
    signInWithPhoneNumber(auth, phoneNumber, appVerifier)
        .then((confirmationResult) => {
          // SMS sent. Prompt user to type the code from the message, then sign the
          // user in with confirmationResult.confirm(code).
          window.confirmationResult = confirmationResult;
          // ...
        }).catch((error) => {
          // Error; SMS not sent
          // ...
        });

    Web version 8

    const phoneNumber = getPhoneNumberFromUserInput();
    const appVerifier = window.recaptchaVerifier;
    firebase.auth().signInWithPhoneNumber(phoneNumber, appVerifier)
        .then((confirmationResult) => {
          // SMS sent. Prompt user to type the code from the message, then sign the
          // user in with confirmationResult.confirm(code).
          window.confirmationResult = confirmationResult;
          // ...
        }).catch((error) => {
          // Error; SMS not sent
          // ...
        });
    如果signInWithPhoneNumber导致错误,请重置 reCAPTCHA,以便用户可以重试:
    grecaptcha.reset(window.recaptchaWidgetId);
    
    // Or, if you haven't stored the widget ID:
    window.recaptchaVerifier.render().then(function(widgetId) {
      grecaptcha.reset(widgetId);
    });
    

signInWithPhoneNumber方法向用户发出 reCAPTCHA 质询,如果用户通过质询,则请求 Firebase 身份验证向用户的手机发送包含验证码的 SMS 消息。

使用验证码登录用户

调用signInWithPhoneNumber成功后,提示用户输入短信收到的验证码。然后,通过将代码传递给ConfirmationResult对象的confirm方法来登录用户,该方法已传递给signInWithPhoneNumber的履行处理程序(即其then块)。例如:

Web version 9

const code = getCodeFromUserInput();
confirmationResult.confirm(code).then((result) => {
  // User signed in successfully.
  const user = result.user;
  // ...
}).catch((error) => {
  // User couldn't sign in (bad verification code?)
  // ...
});

Web version 8

const code = getCodeFromUserInput();
confirmationResult.confirm(code).then((result) => {
  // User signed in successfully.
  const user = result.user;
  // ...
}).catch((error) => {
  // User couldn't sign in (bad verification code?)
  // ...
});

如果confirm调用成功,则用户成功登录。

获取中间 AuthCredential 对象

如果您需要获取用户帐户的AuthCredential对象,请将确认结果中的验证码和验证码传递给PhoneAuthProvider.credential ,而不是调用confirm :

var credential = firebase.auth.PhoneAuthProvider.credential(confirmationResult.verificationId, code);

然后,您可以使用凭据登录用户:

firebase.auth().signInWithCredential(credential);

使用虚构的电话号码进行测试

您可以通过 Firebase 控制台设置用于开发的虚构电话号码。使用虚构的电话号码进行测试可带来以下好处:

  • 在不消耗您的使用配额的情况下测试电话号码身份验证。
  • 在不发送实际 SMS 消息的情况下测试电话号码身份验证。
  • 使用相同的电话号码运行连续测试而不会受到限制。如果审核者碰巧使用相同的电话号码进行测试,这可以最大限度地降低 App Store 审核过程中被拒绝的风险。
  • 无需任何额外工作即可在开发环境中轻松进行测试,例如无需 Google Play 服务即可在 iOS 模拟器或 Android 模拟器中进行开发。
  • 编写集成测试,而不会被通常应用于生产环境中真实电话号码的安全检查所阻止。

虚构电话号码必须满足以下要求:

  1. 确保您使用的电话号码确实是虚构的,并且不存在。 Firebase 身份验证不允许您将真实用户使用的现有电话号码设置为测试号码。一种选择是使用 555 前缀号码作为美国测试电话号码,例如: +1 650-555-3434
  2. 必须针对长度和其他限制正确格式化电话号码。他们仍将通过与真实用户电话号码相同的验证。
  3. 您最多可以添加 10 个电话号码进行开发。
  4. 使用难以猜测的测试电话号码/代码并经常更改。

创建虚构的电话号码和验证码

  1. Firebase 控制台中,打开身份验证部分。
  2. 登录方法选项卡中,启用电话提供商(如果您尚未启用)。
  3. 打开用于测试手风琴的电话号码菜单。
  4. 提供您要测试的电话号码,例如: +1 650-555-3434
  5. 提供该特定号码的 6 位验证码,例如: 654321
  6. 添加号码。如果需要,您可以通过将鼠标悬停在相应行上并单击垃圾桶图标来删除电话号码及其代码。

手动测试

您可以直接在应用程序中开始使用虚构的电话号码。这允许您在开发阶段执行手动测试,而不会遇到配额问题或限制。您也可以直接从没有安装 Google Play 服务的 iOS 模拟器或 Android 模拟器进行测试。

当您提供虚构的电话号码并发送验证码时,不会发送实际的短信。相反,您需要提供之前配置的验证码才能完成登录。

登录完成后,会使用该电话号码创建一个 Firebase 用户。用户具有与真实电话号码用户相同的行为和属性,并且可以以相同的方式访问实时数据库/Cloud Firestore 和其他服务。在此过程中铸造的 ID 令牌与真实电话号码用户具有相同的签名。

如果您想进一步限制访问,另一种选择是通过对这些用户的自定义声明设置测试角色,以将他们区分为假用户。

集成测试

除了手动测试之外,Firebase 身份验证还提供 API 来帮助编写电话身份验证测试的集成测试。这些 API 通过禁用 Web 中的 reCAPTCHA 要求和 iOS 中的静默推送通知来禁用应用程序验证。这使得这些流程中的自动化测试成为可能,并且更易于实施。此外,它们还有助于提供在 Android 上测试即时验证流程的能力。

在 Web 上,在呈现firebase.auth.RecaptchaVerifier之前将appVerificationDisabledForTesting设置为true 。这会自动解析 reCAPTCHA,让您无需手动解析即可传递电话号码。请注意,即使 reCAPTCHA 已禁用,使用非虚构电话号码仍将无法完成登录。此 API 只能使用虚构电话号码。

// Turn off phone auth app verification.
firebase.auth().settings.appVerificationDisabledForTesting = true;

var phoneNumber = "+16505554567";
var testVerificationCode = "123456";

// This will render a fake reCAPTCHA as appVerificationDisabledForTesting is true.
// This will resolve after rendering without app verification.
var appVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container');
// signInWithPhoneNumber will call appVerifier.verify() which will resolve with a fake
// reCAPTCHA response.
firebase.auth().signInWithPhoneNumber(phoneNumber, appVerifier)
    .then(function (confirmationResult) {
      // confirmationResult can resolve with the fictional testVerificationCode above.
      return confirmationResult.confirm(testVerificationCode)
    }).catch(function (error) {
      // Error; SMS not sent
      // ...
    });

禁用应用验证时,可见和不可见模拟 reCAPTCHA 应用验证器的行为不同:

  • Visible reCAPTCHA :当通过appVerifier.render()呈现可见 reCAPTCHA 时,它会在几分之一秒的延迟后自动解析。这相当于用户在渲染后立即单击 reCAPTCHA。 reCAPTCHA 响应将在一段时间后过期,然后再次自动解析。
  • 不可见的 reCAPTCHA :不可见的 reCAPTCHA 不会在呈现时自动解析,而是在appVerifier.verify()调用或在延迟几分之一秒后单击 reCAPTCHA 的按钮锚时自动解析。同样,响应将在一段时间后过期,并且只会在appVerifier.verify()调用之后或再次单击 reCAPTCHA 的按钮锚时自动解析。

每当一个模拟 reCAPTCHA 被解析时,相应的回调函数就会按预期使用假响应触发。如果还指定了过期回调,它将在过期时触发。

下一步

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

  • 在您的应用程序中,了解用户身份验证状态的推荐方法是在Auth对象上设置观察者。然后,您可以从User对象中获取用户的基本配置文件信息。请参阅管理用户

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

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

要注销用户,请调用signOut

Web version 9

import { getAuth, signOut } from "firebase/auth";

const auth = getAuth();
signOut(auth).then(() => {
  // Sign-out successful.
}).catch((error) => {
  // An error happened.
});

Web version 8

firebase.auth().signOut().then(() => {
  // Sign-out successful.
}).catch((error) => {
  // An error happened.
});