高级身份验证功能

1. 设置

获取源代码

在此 Codelab 中,您将从一个几乎完整的 Friendly Chat 示例应用版本开始,因此您需要做的第一件事是克隆源代码:

$ git clone https://github.com/firebase/codelab-friendlychat-web --branch security

然后,进入 security-start 目录,您将在此目录中完成此 Codelab 的剩余部分:

$ cd codelab-friendlychat-web/security-start

现在,安装依赖项,以便您可以运行代码。如果您使用的是较慢的互联网连接,这可能需要一两分钟:

$ npm install && (cd functions && npm install)

了解此代码库

security-solution/ 目录包含示例应用的完整代码。security-start 目录是您完成此 Codelab 的地方,其中缺少身份验证实现的一些重要部分。security-start/security-solution/ 中的关键文件和功能如下:

  • functions/index.js 包含 Cloud Functions 代码,您将在此处编写身份验证拦截函数。
  • public/ - 包含聊天应用的静态文件
  • public/scripts/main.js - 聊天应用 JS 代码 (src/index.js) 的编译位置
  • src/firebase-config.js - 包含用于初始化聊天应用的 Firebase 配置对象
  • src/index.js - 您的 Chat 扩展应用 JS 代码

获取 Firebase CLI

模拟器套件是 Firebase CLI(命令行界面)的一部分,您可以使用以下命令将其安装到您的机器上:

$ npm install -g firebase-tools@latest

使用 webpack 构建 JavaScript,这将在 public/scripts/ 目录中创建 main.js。

webpack build

接下来,确认您使用的是最新版本的 CLI。本 Codelab 适用于 11.14 版或更高版本。

$ firebase --version
11.14.2

关联到 Firebase 项目

创建新的 Firebase 项目

  1. 使用您的 Google 账号登录 Firebase 控制台
  2. 点击相应按钮以创建新项目,然后输入项目名称(例如 Authentication MFA Codelab)。
  3. 点击继续
  4. 如果看到相关提示,请查看并接受 Firebase 条款,然后点击继续
  5. (可选)在 Firebase 控制台中启用 AI 辅助功能(称为“Gemini in Firebase”)。
  6. 在此 Codelab 中,您不需要使用 Google Analytics,因此请关闭 Google Analytics 选项。
  7. 点击创建项目,等待项目完成预配,然后点击继续

将代码关联到 Firebase 项目

现在,您需要将此代码连接到您的 Firebase 项目。首先,运行以下命令以登录 Firebase CLI:

$ firebase login

接下来,运行以下命令以创建项目别名。将 $YOUR_PROJECT_ID 替换为您的 Firebase 项目 ID。

$ firebase use $YOUR_PROJECT_ID

现在,您可以运行应用了!

2. 运行模拟器

在本部分中,您将在本地运行应用。这意味着,现在可以启动 Emulator Suite 了。

启动模拟器

在 Codelab 源代码目录中,运行以下命令以启动模拟器:

$ firebase emulators:start

这将在 http://127.0.0.1:5170 上提供您的应用,并在您进行更改时不断重新构建源代码。您只需在浏览器中强制刷新 (ctrl-shift-r) 本地页面即可看到更改。

您应该会看到类似于以下内容的输出:

i  emulators: Starting emulators: auth, functions, firestore, hosting, storage
✔  functions: Using node@16 from host.
i  firestore: Firestore Emulator logging to firestore-debug.log
✔  firestore: Firestore Emulator UI websocket is running on 9150.
i  hosting[demo-example]: Serving hosting files from: ./public
✔  hosting[demo-example]: Local server: http://127.0.0.1:5170
i  ui: Emulator UI logging to ui-debug.log
i  functions: Watching "[...]" for Cloud Functions...
✔  functions: Loaded functions definitions from source: beforecreated.
✔  functions[us-central1-beforecreated]: providers/cloud.auth/eventTypes/user.beforeCreate function initialized (http://127.0.0.1:5011/[...]/us-central1/beforecreated).
i  Running script: npm start
 
> security@1.0.0 start
> webpack --watch --progress
[...]
webpack 5.50.0 compiled with 1 warning in 990 ms

看到所有模拟器都已准备就绪消息后,即可开始使用该应用。

3. 实现 MFA

此代码库中已部分实现 MFA。您将添加代码,以先为用户注册 MFA,然后提示已注册 MFA 的用户提供第二重身份验证。

在编辑器中,打开 src/index.js 文件,然后找到 startEnrollMultiFactor() 方法。添加以下代码以设置 reCAPTCHA 验证程序,防止电话滥用(reCAPTCHA 验证程序设置为不可见,不会向用户显示):

async function startEnrollMultiFactor(phoneNumber) {
  const recaptchaVerifier = new RecaptchaVerifier(
    "recaptcha",
    { size: "invisible" },
    getAuth()
  );

然后,找到 finishEnrollMultiFactor() 方法并添加以下代码以注册第二重身份验证:

// Completes MFA enrollment once a verification code is obtained.
async function finishEnrollMultiFactor(verificationCode) {
  // Ask user for the verification code. Then:
  const cred = PhoneAuthProvider.credential(verificationId, verificationCode);
  const multiFactorAssertion = PhoneMultiFactorGenerator.assertion(cred);
 
  // Complete enrollment.
  await multiFactor(getAuth().currentUser)
    .enroll(multiFactorAssertion)
    .catch(function (error) {
      alert(`Error finishing second factor enrollment. ${error}`);
      throw error;
    });
  verificationId = null;
}

接下来,找到 signIn 函数并添加以下控制流,以提示已注册 MFA 的用户输入其第二重身份验证信息:

async function signIn() {
  // Sign in Firebase using popup auth and Google as the identity provider.
  var provider = new GoogleAuthProvider();
  await signInWithPopup(getAuth(), provider)
    .then(function (userCredential) {
      // User successfully signed in and is not enrolled with a second factor.
    })
    .catch(function (error) {
      if (error.code == "auth/multi-factor-auth-required") {
        multiFactorResolver = getMultiFactorResolver(getAuth(), error);
        displaySecondFactor(multiFactorResolver.hints);
      } else {
        alert(`Error signing in user. ${error}`);
      }
    });
}

其余实现(包括此处调用的函数)已完成。如需了解其工作原理,请浏览文件的其余部分。

4. 在模拟器中试用 MFA 登录

现在,尝试使用 MFA 实现!确保模拟器仍在运行,然后访问本地托管的应用 (localhost:5170)。尝试登录,当系统提示您提供 MFA 代码时,您会在终端窗口中看到 MFA 代码。

由于模拟器完全支持多重身份验证,因此您的开发环境可以完全自成一体。

如需详细了解如何实现 MFA,请参阅我们的参考文档

5. 创建屏蔽函数

有些应用仅供特定用户群组使用。在这些情况下,您可能希望能够为用户注册或登录您的应用创建自定义要求。

这正是阻塞函数所提供的功能:一种创建自定义身份验证要求的方式。它们是 Cloud Functions,但与大多数函数不同,当用户尝试注册或登录时,它们会同步运行。

如需创建阻塞函数,请在编辑器中打开 functions/index.js,然后找到已注释掉的 beforecreated 函数。

将其替换为以下代码,该代码仅允许域名为 example.com 的用户创建账号:

exports.beforecreated = beforeUserCreated((event) => {
  const user = event.data;
  // Only users of a specific domain can sign up.
  if (!user.email || !user.email.endsWith("@example.com")) {
    throw new HttpsError("invalid-argument", "Unauthorized email");
  }
});

6. 在模拟器中试用屏蔽函数

如需试用屏蔽功能,请确保模拟器正在运行,并在 localhost:5170 的 Web 应用中退出账号。

然后,尝试使用不以 example.com 结尾的电子邮件地址创建账号。阻塞函数会阻止操作成功完成。

现在,请使用以 example.com 结尾的电子邮件地址重试。账号将成功创建。

借助屏蔽函数,您可以根据需要创建任何身份验证限制。如需了解详情,请参阅参考文档

回顾

太棒了!您向 Web 应用添加了多重身份验证,以帮助用户确保账号安全,然后您创建了自定义要求,让用户使用阻塞函数注册。您绝对值得获得一个 GIF!

办公室人员跳“举高双手”舞蹈的 GIF