将您的应用连接到 Authentication 模拟器

在将 Authentication 模拟器用于您的应用之前,请确保您了解 Firebase Local Emulator Suite 的整体工作流,而且已安装和配置 Local Emulator Suite 并已查看其 CLI 命令

本主题假设您已熟悉如何开发用于生产环境的 Firebase Authentication 解决方案。如果需要,请参阅有关平台和身份验证方法组合的文档。

Authentication 模拟器的用途

Authentication 模拟器可以对 Firebase Authentication 服务进行高准确度本地模拟,能提供正式版 Firebase Authentication 的大部分功能。该模拟器可与 Apple 平台、Android 和 Web 版 Firebase SDK 结合使用,支持您执行以下操作:

  • 创建、更新和管理模拟用户账号,用于测试电子邮件地址/密码、电话号码/短信、短信多重身份验证和第三方(例如 Google)身份提供方身份验证
  • 查看和修改模拟用户
  • 进行自定义令牌身份验证系统原型设计
  • 在模拟器界面内的“日志”标签页中,查看与身份验证相关的消息。

选择一个 Firebase 项目

Firebase Local Emulator Suite 模拟的是单个 Firebase 项目的产品。

如需选择要使用的项目,请在启动模拟器之前,使用 CLI 在工作目录下运行 firebase use。或者,您也可以向每个模拟器命令传递 --project 标志。

Local Emulator Suite 支持模拟实际 Firebase 项目和演示项目。

项目类型 特性 与模拟器结合使用
实际项目

实际 Firebase 项目就是您创建和配置的项目(很可能是通过 Firebase 控制台创建和配置)。

实际项目具有实时资源,例如数据库实例、存储桶、函数或您为该 Firebase 项目设置的任何其他资源。

使用实际的 Firebase 项目时,您可以为任何或所有受支持的产品运行模拟器。

对于您未模拟的任何产品,您的应用和代码都将与实时资源(数据库实例、存储桶、函数等)交互。

演示项目

演示 Firebase 项目没有实际 Firebase 配置,也没有实时资源。通常可通过 Codelab 或其他教程来访问这些项目。

演示项目的 ID 带有 demo- 前缀。

使用演示 Firebase 项目时,您的应用和代码仅与模拟器交互。如果您的应用尝试与您没有为其运行模拟器的资源进行交互,该代码将失败。

我们建议您尽可能使用演示项目。演示项目具有以下优势:

  • 设置更简单,您无需创建 Firebase 项目也可运行模拟器
  • 安全性更强,就算您的代码意外调用了非模拟(生产环境)资源,也不可能发生数据更改、使用资源或产生费用
  • 提供更好的离线支持,无需访问互联网即可下载您的 SDK 配置。

对您的应用进行插桩 (instrument) 处理以与模拟器通信

Android、iOS 和 Web SDK

按照以下步骤设置您的应用内配置或测试类,以便与 Authentication 模拟器进行交互。

Kotlin+KTX
Firebase.auth.useEmulator("10.0.2.2", 9099)
Java
FirebaseAuth.getInstance().useEmulator("10.0.2.2", 9099);
Swift
Auth.auth().useEmulator(withHost:"127.0.0.1", port:9099)

Web 模块化 API

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

const auth = getAuth();
connectAuthEmulator(auth, "http://127.0.0.1:9099");

Web 命名空间型 API

const auth = firebase.auth();
auth.useEmulator("http://127.0.0.1:9099");

无需进行额外设置,即可对 Authentication 与 Cloud Functions 或者 Cloud Firestore 或 Realtime Database 的 Firebase 安全规则之间的交互进行原型设计和测试。如果 Authentication 模拟器配置完毕时有其他模拟器正在运行,它们会自动协同工作。

Admin SDK

设置 FIREBASE_AUTH_EMULATOR_HOST 环境变量后,Firebase Admin SDK 会自动连接到 Authentication 模拟器。

export FIREBASE_AUTH_EMULATOR_HOST="127.0.0.1:9099"

请注意,Cloud Functions 模拟器会自动识别 Authentication 模拟器,因此在测试 Cloud Functions 与 Authentication 模拟器之间的集成时,您可以跳过此步骤。系统会自动在 Cloud Functions 中为 Admin SDK 设置该环境变量。

设置好该环境变量后,Firebase Admin SDK 将接受由 Authentication 模拟器签发的未签名 ID 令牌和会话 Cookie(分别通过 verifyIdTokencreateSessionCookie 方法签发),以便于进行本地开发和测试。切勿在生产环境中设置该环境变量。

如果您希望 Admin SDK 代码连接到在其他环境中运行的共享模拟器,则需要指定您使用 Firebase CLI 设置的同一项目 ID。您可以直接将项目 ID 传递给 initializeApp 或设置 GCLOUD_PROJECT 环境变量。

Node.js Admin SDK
admin.initializeApp({ projectId: "your-project-id" });
环境变量
export GCLOUD_PROJECT="your-project-id"

ID 令牌

出于安全考虑,Authentication 模拟器会签发未签名的 ID 令牌,只有其他 Firebase 模拟器或进行了相应配置的 Firebase Admin SDK 才会接受这些令牌。而生产环境中的 Firebase 服务或在生产模式下运行的 Firebase Admin SDK(例如,未进行上述设置步骤的默认行为)会拒绝这些令牌。

启动模拟器

您可以通过 Emulator Suite 界面以交互方式使用 Authentication 模拟器,也可以通过其本地 REST 接口以非交互方式使用 Authentication 模拟器。以下部分介绍了交互式和非交互式使用场景。

如需启动 Authentication 模拟器、其 REST 接口和 Emulator Suite 界面,请执行以下命令:

firebase emulators:start

对于匿名身份验证,您的应用可以采用适用于您的平台(iOSAndroidWeb)的登录逻辑。

对于电子邮件地址/密码身份验证,您可以使用 Authentication SDK 方法或 Emulator Suite 界面从您的应用向 Authentication 模拟器添加用户账号,以开始原型设计。

  1. 在 Emulator Suite 界面中,点击 Authentication 标签页。
  2. 点击添加用户按钮。
  3. 按照用户账号创建向导中的说明,填写电子邮件身份验证字段。

创建测试用户后,您的应用可以使用适用于您的平台(iOSAndroidWeb)的 SDK 逻辑让用户登录或退出登录。

为了测试通过电子邮件链接流进行的电子邮件验证/登录,该模拟器会将网址输出到执行 firebase emulators:start 的终端。

i  To verify the email address customer@ex.com, follow this link:
http://127.0.0.1:9099/emulator/action?mode=verifyEmail&lang=en&oobCode=XYZ123&apiKey=fake-api-key

将链接粘贴到浏览器中以模拟验证事件,并检查验证是否成功执行。

{
  "authEmulator": {
    "success": "The email has been successfully verified.",
    "email": "customer@example.com"
  }
}

为了测试密码重置,模拟器会将一个包含 newPassword 参数(您可根据需要更改)的类似网址输出到终端。

http://127.0.0.1:9099/emulator/action?mode=resetPassword&oobCode=XYZ!23&apiKey=fake-api-key&newPassword=YOUR_NEW_PASSWORD

非交互式测试

您可以编写测试设置脚本,在其中调用 REST API 来创建和删除用户账号,并提取带外电子邮件验证码来填充模拟器电子邮件验证网址,而不是使用 Emulator Suite 界面或客户端代码来管理电子邮件地址/密码用户账号。这样可以将平台和测试代码分开,并可让您以非交互方式测试。

对于非交互式电子邮件地址和密码测试流程,典型的操作顺序如下:

  1. 使用 Authentication signUp REST 端点创建用户。
  2. 使用电子邮件地址和密码登录用户,以进行测试。
  3. 特定于模拟器的 REST 端点提取可用的带外电子邮件验证码(如果适用于您的测试的话)。
  4. 使用特定于模拟器的 REST 端点刷新用户记录,以便清除数据。

模拟电话/短信身份验证

对于电话身份验证,Auth 模拟器不支持以下功能:

  • reCAPTCHA 和 APN 流。一旦配置为与模拟器交互,客户端 SDK 就会停用这些验证方法,具体方式类似于针对集成测试(iOSAndroidWeb)所述的方式。
  • 使用在 Firebase 控制台中预配置的代码测试电话号码。

除此之外,在客户端代码方面,电话/短信身份验证流程与针对生产环境(iOSAndroidWeb)所述的流程完全相同。

使用 Emulator Suite 界面:

  1. 在 Emulator Suite 界面中,点击 Authentication 标签页。
  2. 点击添加用户按钮。
  3. 按照用户账号创建向导中的说明,填写电话身份验证字段。

不过,对于电话身份验证流程,模拟器不会触发任何实际的短信传送,因为联系运营商的操作超出了范围,不适用于本地测试!作为替代办法,模拟器会将本该通过短信发出的验证码输出到您运行 firebase emulators:start 的同一终端;将此验证码输入到应用中可以模拟用户查看短信的过程。

非交互式测试

对于非交互式电话身份验证测试,请使用 Authentication 模拟器 REST API 检索提供的短信验证码。请注意,每次启动该流程时,验证码都不同。

典型的操作顺序如下。

  1. 调用平台 signInWithPhoneNumber 以开始验证流程。
  2. 使用特定于模拟器的 REST 端点检索验证码。
  3. 像往常一样使用验证码调用 confirmationResult.confirm(code)

多重身份验证短信

Authentication 模拟器支持对 iOSAndroidWeb 生产环境中可用的短信多重身份验证 (MFA) 流程进行原型设计和测试。

将模拟用户添加到模拟器时,您可以启用 MFA 并配置一个或多个用于接收第二重身份验证短信的电话号码。短信会输出到您运行 firebase emulators:start 的终端,或者可通过 REST 接口获取。

模拟第三方身份提供方 (IDP) 身份验证

通过 Authentication 模拟器,您可以在 iOS、Android 或 Web 应用中测试许多第三方身份验证流程,而无需更改生产代码。如需获取身份验证流程的示例,请参阅关于可在应用中使用的各种提供方和平台组合的文档。

一般来说,您可以通过以下两种方式之一使用 Firebase SDK 进行身份验证:

  • 您的应用让 SDK 端到端地处理整个流程,包括与第三方身份提供方进行所有交互以检索凭据。
  • 您的应用使用第三方提供方的 SDK 从该第三方处手动检索凭据,并将这些凭据传递给 Authentication SDK。

再次重申,请参阅上述文档链接指向的内容,确保您熟悉要使用的任何流程,无论是 Firebase SDK 代管的凭据检索还是手动凭据检索。Authentication 模拟器支持使用任一方法进行测试。

测试由 Firebase SDK 驱动的 IDP 流程

如果您的应用使用任何 Firebase SDK 端到端流程(如使用 OAuthProvider 通过 Microsoft、GitHub 或 Yahoo 登录)进行交互测试,Authentication 模拟器将提供对应登录页面的本地版本,帮助您测试从调用 signinWithPopupsignInWithRedirect 方法的 Web 应用进行的身份验证。本地提供的登录页面也会在移动应用中显示,由平台的 WebView 库呈现。

在流程执行的过程中,模拟器会根据需要创建模拟第三方用户账号和凭据。

使用手动凭据检索测试 IDP 流程

如果您使用“手动”登录技术并调用平台的 signInWithCredentials 方法,您的应用将照常请求实际的第三方登录逻辑并检索实际的第三方凭据。

请注意,模拟器仅支持对从 Google 登录、Apple 以及其他使用 JSON Web 令牌 (JWT) 格式 ID 令牌的提供方处获取的凭据执行 signInWithCredential 身份验证。访问令牌(例如 Facebook 或 Twitter 提供的令牌,它们不是 JWT)不受支持。下一部分将讨论此类情况下可使用的替代方案。

非交互式测试

一种非交互式测试方法是在模拟器提供的登录页面上自动进行用户点击。对于 Web 应用,请使用 WebDriver 等控制界面。对于移动应用,请使用您的平台中的界面测试工具,例如 Espresso 或 Xcode。

或者,您也可以将代码更新为使用 signInWithCredential(例如在代码分支中),并将令牌身份验证流程与账号的模拟 ID 令牌(而非实际凭据)结合使用。

  1. 改写或注释掉代码中用于从 IDP 检索 idToken 的部分;这样就无需在测试期间输入实际的用户名和密码,并让您的测试不受 IDP 的 API 配额和速率限制。
  2. 接着,使用字面量 JSON 字符串代替 signInWithCredential 的令牌。以 Web SDK 为例,您可以将代码更改为:
firebase.auth().signInWithCredential(firebase.auth.GoogleAuthProvider.credential(
  '{"sub": "abc123", "email": "foo@example.com", "email_verified": true}'
));

与模拟器搭配使用时,此代码会成功地用电子邮件地址 foo@example.com 在 Google 上验证用户的身份。不妨将子字段看作可以改成任何字符串的主键,从而模拟不同用户的登录。例如,您可以将 firebase.auth.GoogleAuthProvider 替换为 new firebase.auth.OAuthProvider('yahoo.com') 或您要模拟的任何其他提供方 ID。

模拟的自定义令牌身份验证

Authentication 模拟器通过对支持的平台调用 signInWithCustomToken 方法,使用自定义 JSON Web 令牌处理身份验证操作,如正式版 Authentication 文档中所述。

Authentication 模拟器与生产环境的区别

Firebase Authentication 模拟器可模拟生产环境产品的许多功能。但是,由于任何类型的身份验证系统都严重依赖多个级别(设备、第三方提供方、Firebase 等)的安全性,因此模拟器很难适当地重新创建所有流程。

Cloud IAM

Firebase Emulator Suite 不会尝试复制或遵从任何与 IAM 相关的运行行为。模拟器遵循提供的 Firebase 安全规则,但在通常会使用 IAM 的情况下(例如,用来设置 Cloud Functions 函数调用服务账号以及权限等),模拟器不可配置,并且将使用开发者机器上的全局可用账号(类似于直接运行本地脚本)。

在移动平台上,由于电子邮件链接登录依赖于 Firebase Dynamic Links,因此所有这类链接都将改为在(移动)Web 平台上打开。

第三方登录

对于第三方登录流程,Firebase Authentication 依赖来自 Twitter 和 GitHub 等第三方提供方的安全凭据。

Authentication 模拟器接受来自 OpenID Connect 提供方(如 Google 和 Apple)的真实凭据。来自非 OpenID Connect 提供方的凭据不受支持。

电子邮件/短信登录

在生产应用中,电子邮件和短信登录流程包含一个异步操作,以便让用户查看收到的信息,并在登录界面上输入登录验证码。Authentication 模拟器不会发送任何电子邮件或短信,但如上所述,它会生成登录验证码,并将其输出到终端以供测试使用。

模拟器并不能像 Firebase 控制台一样支持使用固定的登录验证码定义测试电话号码。

自定义令牌身份验证

Authentication 模拟器不会验证自定义令牌的签名或过期时间。这样,您就可以在原型设计和测试场景中使用专门编写的令牌,并可以无限期地重复使用。

速率限制/防滥用

Authentication 模拟器不会复制生产速率限制和防滥用功能。

屏蔽函数

在生产环境中,beforeCreatebeforeSignIn 事件触发后,系统会将用户写入存储空间一次。不过,由于技术限制,Authentication 模拟器会向存储区写入两次,一次是在创建用户以后,另一次在登录以后。这意味着,对于新用户,您可以在 Authentication 模拟器的 beforeSignIn 中成功调用 getAuth().getUser(),但在生产环境中进行这样的调用却会遇到错误。

后续步骤