AngularFire Web Codelab

1. 概览

在此 Codelab 中,您将学习如何使用 AngularFire 通过使用 Firebase 产品和服务实现和部署聊天客户端来创建 Web 应用。

用户讨论 Firebase 的聊天应用

学习内容

  • 使用 Angular 和 Firebase 构建 Web 应用。
  • 使用 Cloud Firestore 和 Cloud Storage for Firebase 同步数据。
  • 使用 Firebase Authentication 对您的用户进行身份验证。
  • 在 Firebase App Hosting 上部署您的 Web 应用。
  • 使用 Firebase Cloud Messaging 发送通知。
  • 收集 Web 应用的性能数据。

您需要满足的条件

  • GitHub 账号
  • 能够将 Firebase 项目升级为 Blaze 定价方案
  • 您选择的 IDE/文本编辑器,例如 WebStormSublimeVS Code
  • 软件包管理器 npm(通常随 Node.js 一起提供)
  • 终端/控制台
  • 您所选的浏览器(例如 Chrome)
  • 此 Codelab 的示例代码(请参阅 Codelab 的下一步,了解如何获取代码)。

2. 获取示例代码

创建一个 GitHub 代码库。

您可以在 https://github.com/firebase/codelab-friendlychat-web 找到此 Codelab 的源代码。该代码库包含适用于多个平台的示例项目。不过,此 Codelab 仅使用 angularfire-start 目录。

angularfire-start 文件夹复制到您自己的代码库中:

  1. 使用终端在计算机上创建一个新文件夹,然后切换到该新目录:
    mkdir codelab-friendlyeats-web
    
    cd codelab-friendlyeats-web
    
  2. 使用 giget npm 软件包仅提取 angularfire-start 文件夹:
    npx giget@latest gh:firebase/codelab-friendlychat-web/angularfire-start#master . --install
    
  3. 使用 git 在本地跟踪更改:
    git init
    
    git add .
    
    git commit -m "codelab starting point"
    
    git branch -M main
    
  4. 创建新的 GitHub 代码库:https://github.com/new。您可以随意为其命名。
    1. GitHub 会为您提供一个新的代码库网址,网址类似于 https://github.com/[user-name]/[repository-name].git[email protected]:[user-name]/[repository-name].git。复制此网址。
  5. 将本地更改推送到新的 GitHub 代码库。运行以下命令,将您的代码库网址替换为 your-repository-url 占位符。
    git remote add origin your-repository-url
    
    git push -u origin main
    
  6. 现在,您应该会在 GitHub 代码库中看到起始代码。

3. 创建和设置 Firebase 项目

创建 Firebase 项目

  1. 登录 Firebase 控制台
  2. 在 Firebase 控制台中,点击 Add Project,然后将您的 Firebase 项目命名为 FriendlyChat。记住您的 Firebase 项目的项目 ID。
  3. 取消选中为此项目启用 Google Analytics
  4. 点击创建项目

您将要构建的应用会使用适用于 Web 应用的 Firebase 产品:

  • Firebase Authentication,可让用户轻松登录您的应用。
  • Cloud Firestore:用于在云端保存结构化数据,并在数据发生变化时即时收到通知。
  • Cloud Storage for Firebase,用于在云端保存文件。
  • Firebase App Hosting,用于构建、托管和分发应用。
  • Firebase 云消息传递,用于发送推送通知和显示浏览器弹出式通知。
  • Firebase Performance Monitoring,用于收集应用的用户性能数据。

其中一些产品需要进行特殊配置,或需要使用 Firebase 控制台启用。

升级您的 Firebase 定价方案

如需使用 Firebase App Hosting 和 Cloud Storage for Firebase,您的 Firebase 项目必须采用随用随付(Blaze)定价方案,这意味着该项目已与一个 Cloud Billing 账号相关联。

  • Cloud Billing 账号要求提供付款方式,例如信用卡。
  • 如果您刚开始接触 Firebase 和 Google Cloud,请确认您是否有资格获得 $300 赠金和免费试用 Cloud Billing 账号
  • 如果您是在某个活动中学习本 Codelab,请询问组织者是否有 Cloud 抵用金。

如需将项目升级到 Blaze 方案,请按以下步骤操作:

  1. 在 Firebase 控制台中,选择升级您的方案
  2. 选择 Blaze 方案。按照屏幕上的说明将 Cloud Billing 账号与您的项目相关联。
    如果您需要在此升级过程中创建 Cloud Billing 账号,则可能需要返回 Firebase 控制台中的升级流程以完成升级。

向项目添加 Firebase Web 应用

  1. 点击 Web 图标 58d6543a156e56f9.png 以创建新的 Firebase Web 应用。
  2. 使用昵称 Friendly Chat 注册应用。请勿选中还为此应用设置 Firebase Hosting 旁边的复选框。点击注册应用
  3. 在下一步中,您会看到一个配置对象。您目前无需执行任何操作。点击继续前往控制台

注册 Web 应用屏幕截图

设置身份验证

如需允许用户使用其 Google 账号登录 Web 应用,您将使用 Google 登录方法。

  1. 在 Firebase 控制台中,前往身份验证
  2. 点击开始使用
  3. 其他提供商列中,点击 Google > 启用
  4. 项目的公开名称文本框中,输入一个容易记住的名称,例如 My Next.js app
  5. 项目的支持电子邮件地址下拉列表中,选择您的电子邮件地址。
  6. 点击保存

设置 Cloud Firestore

Web 应用使用 Cloud Firestore 保存聊天消息并接收新聊天消息。

如需在 Firebase 项目中设置 Cloud Firestore,请按以下步骤操作:

  1. 在 Firebase 控制台的左侧面板中,展开构建,然后选择 Firestore 数据库
  2. 点击创建数据库
  3. 数据库 ID 设置为 (default)
  4. 为数据库选择一个位置,然后点击下一步
    对于真实应用,您需要选择靠近用户的位置。
  5. 点击以测试模式启动。阅读有关安全规则的免责声明。
    在本 Codelab 的后面部分,您将添加安全规则来保护您的数据。在没有为数据库添加安全规则的情况下,请不要公开分发或公开应用。
  6. 点击创建

设置 Cloud Storage for Firebase

Web 应用使用 Cloud Storage for Firebase 存储、上传和分享图片。

如需在 Firebase 项目中设置 Cloud Storage for Firebase,请按以下步骤操作:

  1. 在 Firebase 控制台的左侧面板中,展开构建,然后选择存储
  2. 点击开始使用
  3. 为默认的 Storage 存储分区选择位置。
    US-WEST1US-CENTRAL1US-EAST1 中的存储分区可以使用 Google Cloud Storage 的“始终免费”层级。所有其他位置的存储分区均遵循 Google Cloud Storage 价格和使用量
  4. 点击以测试模式启动。阅读有关安全规则的免责声明。
    在本 Codelab 的后面部分,您将添加安全规则来保护您的数据。在未为您的存储桶添加安全规则的情况下,请不要公开分发或公开应用。
  5. 点击创建

4. 安装 Firebase 命令行界面

借助 Firebase 命令行界面 (CLI),您可以使用 Firebase Hosting 在本地提供 Web 应用,以及将 Web 应用部署到 Firebase 项目。

  1. 通过运行以下 npm 命令来安装 CLI:
npm -g install firebase-tools@latest
  1. 通过运行以下命令来验证 CLI 是否已正确安装:
firebase --version

确保 Firebase CLI 版本为 vv13.9.0 或更高版本。

  1. 通过运行以下命令向 Firebase CLI 授权:
firebase login

您已设置 Web 应用模板,以便从应用的本地目录(您在 Codelab 中先前克隆的代码库)中提取应用的 Firebase Hosting 配置。不过,若要拉取配置,您需要将应用与 Firebase 项目相关联。

  1. 确保命令行可以访问应用的本地 angularfire-start 目录。
  2. 通过运行以下命令,将您的应用与 Firebase 项目相关联:
firebase use --add
  1. 当系统提示时,选择您的项目 ID,然后为您的 Firebase 项目指定一个别名。

如果您有多个环境(生产、预演等),别名会非常有用。不过,在此 Codelab 中,我们直接使用 default 这个别名。

  1. 请按照命令行中的其余说明进行操作。

5. 安装 AngularFire

在运行项目之前,请确保您已设置 Angular CLI 和 AngularFire。

  1. 在控制台中,运行以下命令:
npm install -g @angular/cli
  1. 然后,在 angularfire-start 目录的控制台中,运行以下 Angular CLI 命令:
ng add @angular/fire

这将为您的项目安装所有必要的依赖项。

  1. 出现提示时,使用空格键取消选中 ng deploy -- hosting。使用方向键和空格键选择以下功能:
    • Authentication
    • Firestore
    • Cloud Messaging
    • Cloud Storage
  2. enter 键,然后按照剩余的提示操作。
  3. 创建一条提交消息为“Install AngularFire”的提交,并将其推送到您的 GitHub 代码库。

6. 创建 App Hosting 后端

在本部分中,您将设置一个 App Hosting 后端来监控 git 代码库中的分支。

在本部分结束时,您将拥有一个与 GitHub 中的代码库关联的 App Hosting 后端,每当您将新的提交推送到 main 分支时,该后端都会自动重新构建并发布应用的新版本。

  1. 前往 Firebase 控制台中的“App Hosting”页面

App Hosting 控制台的零状态,其中显示了“开始使用”按钮

  1. 点击“开始”以开始后端创建流程。按如下方式配置后端:
  2. 按照第一步中的提示连接您之前创建的 GitHub 代码库。
  3. 设置部署设置:
    1. 将根目录保留为 /
    2. 将正式版分支设置为 main
    3. 启用自动发布
  4. 将后端命名为 friendlychat-codelab
  5. 在“创建或关联 Firebase Web 应用”中,从“选择现有的 Firebase Web 应用”下拉菜单中选择您之前配置的 Web 应用。
  6. 点击“Finish and deploy”(完成并部署)。片刻后,您会进入一个新页面,在其中查看新的 App Hosting 后端的状态!
  7. 发布完成后,点击“网域”下的免费网域。由于 DNS 传播,此操作可能需要几分钟才能开始生效。

您已部署初始 Web 应用!每当您将新提交推送到 GitHub 代码库的 main 分支时,Firebase 控制台中都会显示系统开始进行新的构建和发布,并且您的网站会在发布完成后自动更新。

App Hosting 控制台的零状态,其中显示了“开始使用”按钮

您应该会看到 FriendlyChat 应用的登录界面,该界面(还)无法正常运行。

应用现在无法执行任何操作,不过,在您的帮助下,它很快就能执行操作了!

现在,我们来构建一个实时聊天应用。

7. 导入和配置 Firebase

配置 Firebase

您需要配置 Firebase SDK,以告知其您使用的是哪个 Firebase 项目。

  1. 前往 Firebase 控制台中的项目设置
  2. 在“您的应用”卡片中,选择您需要为其添加配置对象的应用的别名。
  3. 从 Firebase SDK 代码段窗格中选择“配置”。

您会发现系统为您生成了一个环境文件 /angularfire-start/src/environments/environment.ts

  1. 复制配置对象代码段,然后将其添加到 angularfire-start/src/firebase-config.js

environment.ts

export const environment = {
  firebase: {
    apiKey: "API_KEY",
    authDomain: "PROJECT_ID.firebaseapp.com",
    projectId: "PROJECT_ID",
    storageBucket: "PROJECT_ID.firebasestorage.app",
    messagingSenderId: "SENDER_ID",
    appId: "APP_ID",
  },
};

查看 AngularFire 设置

您会发现,您在控制台中选择的功能已自动添加到 /angularfire-start/src/app/app.config.ts 文件中。这样,您的应用便可以使用 Firebase 特性和功能。

8. 设置用户登录

由于 AngularFire 已在 app.config.ts 中导入并初始化,因此现在应该可以使用了。现在,您将使用 Firebase Authentication 实现用户登录。

添加授权网域

Firebase Authentication 仅允许从您控制的一组网域进行登录。将您的免费应用托管网域添加到网域列表中:

  1. 前往 App Hosting
  2. 复制后端的网域。
  3. 前往身份验证设置
  4. 选择已获授权的网域标签页。
  5. 点击添加网域,然后粘贴您的 App Hosting 后端的网域。

使用 Google 登录对用户进行身份验证

在应用中,当用户点击 Sign in with Google 按钮时,系统会触发 login 函数。在此 Codelab 中,您需要授权 Firebase 使用 Google 作为身份提供方。您将使用弹出式窗口,但 Firebase 还提供多种其他方法

  1. 在子目录 /src/app/services/ 中,打开 chat.service.ts
  2. 找到 login 函数。
  3. 将整个函数替换为以下代码。

chat.service.ts

// Signs-in Friendly Chat.
login() {
    signInWithPopup(this.auth, this.provider).then((result) => {
        const credential = GoogleAuthProvider.credentialFromResult(result);
        this.router.navigate(['/', 'chat']);
        return credential;
    })
}

当用户点击退出按钮时,系统会触发 logout 函数。

  1. 返回至 src/app/services/chat.service.ts 文件。
  2. 找到 logout 函数。
  3. 将整个函数替换为以下代码。

chat.service.ts

// Logout of Friendly Chat.
logout() {
    signOut(this.auth).then(() => {
        this.router.navigate(['/', 'login'])
        console.log('signed out');
    }).catch((error) => {
        console.log('sign out error: ' + error);
    })
}

跟踪身份验证状态

为了相应地更新界面,您需要一种方法来检查用户是处于登录状态还是处于退出状态。AngularFire 提供了一个函数,用于获取一个可观察对象,该对象会在每次身份验证状态发生变化时更新。这项功能已实现,但值得您了解一下。

  1. 返回至 src/app/services/chat.service.ts 文件。
  2. 找到变量赋值 user$

chat.service.ts

// observable that is updated when the auth state changes
user$ = user(this.auth);

上面的代码会调用 AngularFire 函数 user,该函数会返回一个可观察的用户。每当身份验证状态发生变化(用户登录或退出登录时)时,系统都会触发该事件。FriendlyChat 中的 Angular 模板组件使用此可观察对象来更新界面以进行重定向、在标题导航栏中显示用户等。

测试登录应用

  1. 创建一条提交消息为“Adding Google Authentication”的提交,并将其推送到您的 GitHub 代码库。
  2. 在 Firebase 控制台中打开 App Hosting 页面,然后等待新的发布完成。
  3. 在 Web 应用中,刷新页面,然后使用登录按钮和您的 Google 账号登录应用。如果您看到提及 auth/operation-not-allowed 的错误消息,请检查并确保您已在 Firebase 控制台中将 Google 登录启用为身份验证提供方。
  4. 登录后,系统应会显示您的个人资料照片和用户名:angularfire-3.png

9. 将消息写入 Cloud Firestore

在本部分中,您需要将一些数据写入 Cloud Firestore,以填充应用的界面。此操作可以使用 Firebase 控制台手动完成,但在这里,您需要在应用内完成,目的是演示基本 Cloud Firestore 写入过程。

数据模型

Cloud Firestore 数据分为集合、文档、字段和子集合。您将以文档形式将聊天中的每条消息存储在名为 messages 的顶级集合中。

688d7bc5fb662b57.png

向 Cloud Firestore 添加消息

如需存储用户撰写的聊天消息,您将使用 Cloud Firestore

在本部分中,您将添加一项功能,让用户可以向数据库写入新消息。用户点击 SEND 按钮会触发以下代码段。它会将包含消息字段内容的消息对象添加到 messages 集合中的 Cloud Firestore 实例。add() 方法会向集合添加一个具有自动生成 ID 的新文档。

  1. 返回至 src/app/services/chat.service.ts 文件。
  2. 找到 addMessage 函数。
  3. 将整个函数替换为以下代码。

chat.service.ts

// Adds a text or image message to Cloud Firestore.
addMessage = async (
  textMessage: string | null,
  imageUrl: string | null,
): Promise<void | DocumentReference<DocumentData>> => {
  // ignore empty messages
  if (!textMessage && !imageUrl) {
    console.log(
      "addMessage was called without a message",
      textMessage,
      imageUrl,
    );
    return;
  }

  if (this.currentUser === null) {
    console.log("addMessage requires a signed-in user");
    return;
  }

  const message: ChatMessage = {
    name: this.currentUser.displayName,
    profilePicUrl: this.currentUser.photoURL,
    timestamp: serverTimestamp(),
    uid: this.currentUser?.uid,
  };

  textMessage && (message.text = textMessage);
  imageUrl && (message.imageUrl = imageUrl);

  try {
    const newMessageRef = await addDoc(
      collection(this.firestore, "messages"),
      message,
    );
    return newMessageRef;
  } catch (error) {
    console.error("Error writing new message to Firebase Database", error);
    return;
  }
};

测试发送消息

  1. 创建一个提交,并将提交消息设为“将新对话发布到 Firestore”,然后将其推送到 GitHub 代码库。
  2. 在 Firebase 控制台中打开 App Hosting 页面,然后等待新的发布完成。
  3. 刷新 FriendlyChat。登录后,输入消息(例如“您好!”),然后点击发送。这会将消息写入 Cloud Firestore。不过,您不会在实际 Web 应用中看到数据,因为您仍需实现数据的检索(在 Codelab 的下一部分中实施)。
  4. 您可以在 Firebase 控制台中看到新添加的消息。打开 Emulator Suite 界面。在构建部分下,点击 Firestore 数据库(或点击此处),您应该会看到包含新添加的消息的消息集合:

6812efe7da395692.png

10. 读取消息

同步消息

如需在应用中读取消息,您需要添加一个会在数据发生变化时触发的观察器,然后创建一个用于显示新消息的界面元素。

您将添加可监听应用中新增消息的代码。在此代码中,您将检索 messages 集合的快照。您将仅显示聊天的最后 12 条消息,以免加载时显示过长的历史记录。

  1. 返回至 src/app/services/chat.service.ts 文件。
  2. 找到 loadMessages 函数。
  3. 将整个函数替换为以下代码。

chat.service.ts

// Loads chat message history and listens for upcoming ones.
loadMessages = () => {
  // Create the query to load the last 12 messages and listen for new ones.
  const recentMessagesQuery = query(collection(this.firestore, 'messages'), orderBy('timestamp', 'desc'), limit(12));
  // Start listening to the query.
  return collectionData(recentMessagesQuery);
}

如需监听数据库中的消息,您可以使用 collection 函数指定要监听的数据所在的集合,从而针对该集合创建查询。在上面的代码中,您监听的是 messages 集合中的更改,聊天消息就存储在该集合中。您还通过使用 limit(12) 仅监听最近 12 条消息,并使用 orderBy('timestamp', 'desc') 按日期对消息进行排序来获取最新的 12 条消息,从而应用了限制。

collectionData 函数在后台使用快照。当与查询匹配的文档发生任何更改时,系统都会触发回调函数。这可能是由于有消息被删除、修改或添加所致。如需了解详情,请参阅 Cloud Firestore 文档

测试同步消息

  1. 创建一个提交,并将提交消息设为“在界面中显示新对话”,然后将其推送到您的 GitHub 代码库。
  2. 在 Firebase 控制台中打开 App Hosting 页面,然后等待新的发布完成。
  3. 刷新 FriendlyChat。您之前在数据库中创建的消息应显示在 FriendlyChat 界面中(见下文)。您可以随意撰写新消息,它们应该会立即显示。
  4. (可选)您可以尝试直接在模拟器套件的 Firestore 部分中手动删除、修改或添加新消息;所有更改都应反映在界面中。

恭喜!您已在应用中读取 Cloud Firestore 文档!

angularfire-2.png

11. 添加 AI 功能

您将使用 Google AI 为聊天应用添加实用的辅助功能。

获取 Google AI API 密钥

  1. 前往 Google AI Studio,然后点击创建 API 密钥
  2. 选择您为本 Codelab 创建的 Firebase 项目。此提示适用于 Google Cloud 项目,但每个 Firebase 项目都是 Google Cloud 项目。
  3. 点击在现有项目中创建 API 密钥
  4. 复制生成的 API 密钥

安装扩展程序

此扩展程序将部署一个云函数,每当有新文档添加到 Firestore 中的 messages 集合时,该函数就会触发。该函数将调用 Gemini,并将其响应写回文档中的 response 字段。

  1. Build Chatbot with the Gemini API 扩展程序页面上,点击在 Firebase 控制台中安装
  2. 请按照提示操作。进入配置扩展程序步骤后,设置以下参数值:
    • Gemini API 提供方:Google AI
    • Google AI API 密钥:粘贴您之前创建的密钥,然后点击创建密钥
    • Firestore 集合路径:messages
    • 提示字段:text
    • 响应字段:response
    • 订单字段:timestamp
    • 上下文:Keep your answers short, informal, and helpful. Use emojis when possible.
  3. 点击安装扩展程序
  4. 等待扩展程序安装完成

测试 AI 功能

FriendlyChat 已经包含用于读取 AI 扩展程序响应的代码。只需发送一条新聊天消息即可试用!

  1. 打开 FriendlyChat 并发送消息。
  2. 片刻之后,您应该会在消息旁边看到一条弹出式回复。该评价末尾带有一个 ✨ ai generated 备注,以明确说明该评价是由生成式 AI 而非真实用户创建的。

12. 发送图片

您现在将添加一种功能,可以共享图片。

虽然 Cloud Firestore 非常适合存储结构化数据,但 Cloud Storage 更适合存储文件。Cloud Storage for Firebase 是一种文件/blob 存储服务,您将使用它来存储用户使用我们应用分享的所有图片。

将图片保存到 Cloud Storage

在此 Codelab 中,我们已经为您添加了一个会触发文件选择器对话框的按钮。选择文件后,系统会调用 saveImageMessage 函数,您可以获得对选定文件的引用。saveImageMessage 函数会执行以下操作:

  1. 在聊天 Feed 中创建“占位符”聊天消息,以便在您上传图片时,用户看到“正在加载”动画。
  2. 将图片文件上传到 Cloud Storage 的以下路径:/<uid>/<file_name>
  3. 为图片文件生成可公开读取的网址。
  4. 使用新上传图片文件的网址更新聊天消息,以取代暂时加载图像。

现在,您将添加发送图片的功能:

  1. 返回至 src/chat.service.ts 文件。
  2. 找到 saveImageMessage 函数。
  3. 将整个函数替换为以下代码。

chat.service.ts

// Saves a new message containing an image in Firestore.
// This first saves the image in Firebase storage.
saveImageMessage = async(file: any) => {
  try {
    // 1 - Add a message with a loading icon that will get updated with the shared image.
    const messageRef = await this.addMessage(null, this.LOADING_IMAGE_URL);

    // 2 - Upload the image to Cloud Storage.
    const filePath = `${this.auth.currentUser?.uid}/${file.name}`;
    const newImageRef = ref(this.storage, filePath);
    const fileSnapshot = await uploadBytesResumable(newImageRef, file);

    // 3 - Generate a public URL for the file.
    const publicImageUrl = await getDownloadURL(newImageRef);

    // 4 - Update the chat message placeholder with the image's URL.
    messageRef ?
    await updateDoc(messageRef, {
      imageUrl: publicImageUrl,
      storageUri: fileSnapshot.metadata.fullPath
    }): null;
  } catch (error) {
    console.error('There was an error uploading a file to Cloud Storage:', error);
  }
}

测试发送图片

  1. 创建一个提交,并将提交消息设为“添加了发布图片的功能”,然后将其推送到 GitHub 代码库。
  2. 在 Firebase 控制台中打开 App Hosting 页面,然后等待新的发布完成。
  3. 刷新 FriendlyChat。登录后,点击左下角的图片上传按钮 angularfire-4.png,然后使用文件选择器选择图片文件。如果您需要图片,可以随意使用这张精美的咖啡杯照片
  4. 应用界面中应显示一条新消息,其中包含您选择的图片:angularfire-2.png

如果您未登录而尝试添加图像,将会看到一条错误消息,提示您必须登录才能添加图像。

13. 显示通知

您现在将添加对浏览器通知的支持。当聊天中有新消息发布时,应用会通知用户。Firebase 云消息传递 (FCM) 是一种跨平台消息传递解决方案,可供您免费、可靠地传递消息和通知。

添加 FCM 服务工作线程

网络应用需要一个可以接收和显示网络通知的 service worker

添加 AngularFire 时,应该已经设置了消息传递提供程序,请确保 /angularfire-start/src/app/app.config.ts 的“imports”部分包含以下代码

provideMessaging(() => {
    return getMessaging();
}),

app/app.config.ts

Service Worker 只需加载和初始化 Firebase Cloud Messaging SDK,后者将处理通知显示事宜。

获取 FCM 设备令牌

在设备或浏览器上启用通知后,您会获得一个设备令牌。您可以使用此设备令牌向特定设备或特定浏览器发送通知。

当用户登录时,您可以调用 saveMessagingDeviceToken 函数。您将从浏览器中获取 FCM 设备令牌,并将其保存到 Cloud Firestore 中。

chat.service.ts

  1. 找到 saveMessagingDeviceToken 函数。
  2. 将整个函数替换为以下代码。

chat.service.ts

// Saves the messaging device token to Cloud Firestore.
saveMessagingDeviceToken= async () => {
    try {
      const currentToken = await getToken(this.messaging);
      if (currentToken) {
        console.log('Got FCM device token:', currentToken);
        // Saving the Device Token to Cloud Firestore.
        const tokenRef = doc(this.firestore, 'fcmTokens', currentToken);
        await setDoc(tokenRef, { uid: this.auth.currentUser?.uid });
 
        // This will fire when a message is received while the app is in the foreground.
        // When the app is in the background, firebase-messaging-sw.js will receive the message instead.
        onMessage(this.messaging, (message) => {
          console.log(
            'New foreground notification from Firebase Messaging!',
            message.notification
          );
        });
      } else {
        // Need to request permissions to show notifications.
        this.requestNotificationsPermissions();
      }
    } catch(error) {
      console.error('Unable to get messaging token.', error);
    };
}

不过,此代码最初将无法正常工作。要想让您的应用可以检索设备令牌,用户需要授权应用显示通知(此 Codelab 的下一步)。

请求权限以显示通知

如果用户尚未向您的应用授予显示通知的权限,您将无法获得设备令牌。在这种情况下,您需要调用 requestPermission() 方法,这将显示一个请求此权限的浏览器对话框(在受支持的浏览器中)。

8b9d0c66dc36153d.png

  1. 返回至 src/app/services/chat.service.ts 文件。
  2. 找到 requestNotificationsPermissions 函数。
  3. 将整个函数替换为以下代码。

chat.service.ts

// Requests permissions to show notifications.
requestNotificationsPermissions = async () => {
    console.log('Requesting notifications permission...');
    const permission = await Notification.requestPermission();
    
    if (permission === 'granted') {
      console.log('Notification permission granted.');
      // Notification permission granted.
      await this.saveMessagingDeviceToken();
    } else {
      console.log('Unable to get permission to notify.');
    }
}

获取设备令牌

  1. 创建一个提交,并将提交消息设为“添加了发布图片的功能”,然后将其推送到 GitHub 代码库。
  2. 在 Firebase 控制台中打开 App Hosting 页面,然后等待新的发布完成。
  3. 刷新 FriendlyChat。登录后,系统应显示通知权限对话框:bd3454e6dbfb6723.png
  4. 点击允许
  5. 打开浏览器的 JavaScript 控制台。您应该会看到以下消息:Got FCM device token: cWL6w:APA91bHP...4jDPL_A-wPP06GJp1OuekTaTZI5K2Tu
  6. 复制您的设备令牌。您在 Codelab 的下一阶段中会用到它。

向您的设备发送通知

现在,您已经获得了设备令牌,可以发送通知了。

  1. 打开 Firebase 控制台的“Cloud Messaging”标签页
  2. 点击“新建通知”
  3. 输入通知标题和通知文本。
  4. 点击屏幕右侧的“发送测试邮件”
  5. 输入您从浏览器的 JavaScript 控制台中复制的设备令牌,然后点击加号 ("+") 符号
  6. 点击“测试”

如果您的应用位于前台,您会在 JavaScript 控制台中看到通知。

如果您的应用在后台运行,浏览器中应会显示一条通知,如以下示例所示:

de79e8638a45864c.png

14. Cloud Firestore 安全规则

查看数据库安全规则

Cloud Firestore 使用特定的规则语言定义访问权限、安全性和数据验证。

在此 Codelab 的开头部分设置 Firebase 项目时,您选择了使用“测试模式”默认安全规则,因此未限制对数据存储空间的访问。在 Firebase 控制台数据库部分的规则标签页中,您可以查看和修改这些规则。

目前,您应该会看到默认规则,这些规则不会限制对数据存储区的访问。这意味着任何用户都可以读取和写入数据存储区中的任何集合。

rules_version = '2';

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write;
    }
  }
}

您将使用以下规则更新规则以进行限制:

firestore.rules

rules_version = '2';

service cloud.firestore {
  match /databases/{database}/documents {
    // Messages:
    //   - Anyone can read.
    //   - Authenticated users can add and edit messages.
    //   - Validation: Check name is same as auth token and text length below 300 char or that imageUrl is a URL.
    //   - Deletes are not allowed.
    match /messages/{messageId} {
      allow read;
      allow create, update: if request.auth != null
                    && request.resource.data.name == request.auth.token.name
                    && (request.resource.data.text is string
                      && request.resource.data.text.size() <= 300
                      || request.resource.data.imageUrl is string
                      && request.resource.data.imageUrl.matches('https?://.*'));
      allow delete: if false;
    }
    // FCM Tokens:
    //   - Anyone can write their token.
    //   - Reading list of tokens is not allowed.
    match /fcmTokens/{token} {
      allow read: if false;
      allow write;
    }
  }
}

安全规则应自动更新到您的模拟器套件。

查看 Cloud Storage 安全规则

Firebase 云端存储使用特定的规则语言定义访问权限、安全性和数据验证。

在本 Codelab 开头设置 Firebase 项目时,您选择了使用默认的 Cloud Storage 安全规则,该规则仅允许通过身份验证的用户使用 Cloud Storage。在 Firebase 控制台的“Storage”(存储)部分的“Rules”(规则)标签页中,您可以查看和修改规则。您应该会看到默认规则,该规则允许任何登录用户在您的存储分区中读取和写入任何文件。

rules_version = '2';

service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write: if request.auth != null;
    }
  }
}

您将更新规则以执行以下操作:

  • 允许每位用户仅写入自己的特定文件夹
  • 允许任何人从 Cloud Storage 读取数据
  • 确保上传的文件是图片
  • 将可上传图片的大小限制为 5 MB 上限

这可以使用以下规则来实现:

storage.rules

rules_version = '2';

// Returns true if the uploaded file is an image and its size is below the given number of MB.
function isImageBelowMaxSize(maxSizeMB) {
  return request.resource.size < maxSizeMB * 1024 * 1024
      && request.resource.contentType.matches('image/.*');
}

service firebase.storage {
  match /b/{bucket}/o {
    match /{userId}/{messageId}/{fileName} {
      allow write: if request.auth != null && request.auth.uid == userId && isImageBelowMaxSize(5);
      allow read;
    }
  }
}

15. 恭喜!

您已使用 Firebase 构建了一个实时聊天 Web 应用!

您学到的内容

  • Firebase App Hosting
  • Firebase Authentication
  • Cloud Firestore
  • Firebase SDK for Cloud Storage
  • Firebase Cloud Messaging
  • Firebase Performance Monitoring

后续步骤

了解详情

16. [可选] 使用 App Check 强制执行

Firebase App Check 有助于保护您的服务免受不需要的流量影响,并帮助保护您的后端免遭滥用。在此步骤中,您将添加凭据验证,并使用 App Check 和 reCAPTCHA Enterprise 屏蔽未经授权的客户端。

首先,您需要启用 App Check 和 reCAPTCHA。

启用 reCaptcha Enterprise

  1. 在 Cloud 控制台中,找到“安全”下方的 reCaptcha Enterprise,然后选择该选项。
  2. 按照提示启用该服务,然后点击创建密钥
  3. 按照提示输入显示名称,然后选择网站作为平台类型。
  4. 将已部署的网址添加到网域列表,并确保未选择“使用复选框验证”选项。
  5. 点击创建密钥,然后将生成的密钥存储在安全的地方。您将在本步骤的后面部分需要它。

启用 App Check

  1. 在 Firebase 控制台中,在左侧面板中找到构建部分。
  2. 点击 App Check,然后点击 Sign-in method 标签页以前往 App Check
  3. 点击注册,然后在出现提示时输入您的 reCAPTCHA Enterprise 密钥,最后点击保存
  4. 在“API”视图中,选择存储,然后点击强制执行。对 Cloud Firestore 执行相同的操作。

App Check 现在应已强制执行!刷新应用,然后尝试查看或发送聊天消息。您应该会收到以下错误消息:

Uncaught Error in snapshot listener: FirebaseError: [code=permission-denied]: Missing or insufficient permissions.

这意味着 App Check 默认会屏蔽未验证的请求。现在,我们来为应用添加验证功能。

前往 environment.ts 文件,并将 reCAPTCHAEnterpriseKey 添加到 environment 对象。

export const environment = {
  firebase: {
    apiKey: 'API_KEY',
    authDomain: 'PROJECT_ID.firebaseapp.com',
    databaseURL: 'https://PROJECT_ID.firebaseio.com',
    projectId: 'PROJECT_ID',
    storageBucket: 'PROJECT_ID.firebasestorage.app',
    messagingSenderId: 'SENDER_ID',
    appId: 'APP_ID',
    measurementId: 'G-MEASUREMENT_ID',
  },
  reCAPTCHAEnterpriseKey: {
    key: "Replace with your recaptcha enterprise site key"
  },
};

key 的值替换为您的 reCAPTCHA 企业版令牌。

然后,前往 app.config.ts 文件并添加以下导入内容:

import { getApp } from '@angular/fire/app';
import {
  ReCaptchaEnterpriseProvider,
  initializeAppCheck,
  provideAppCheck,
} from '@angular/fire/app-check';

在同一 app.config.ts 文件中,添加以下全局变量声明:

declare global {
  var FIREBASE_APPCHECK_DEBUG_TOKEN: boolean;
}

@NgModule({ ...

在导入项中,使用 ReCaptchaEnterpriseProvider 添加 App Check 的初始化,并将 isTokenAutoRefreshEnabled 设置为 true,以允许令牌自动刷新。

imports: [
BrowserModule,
AppRoutingModule,
CommonModule,
FormsModule,
provideFirebaseApp(() => initializeApp(environment.firebase)),
provideAppCheck(() => {
const appCheck = initializeAppCheck(getApp(), {
  provider: new ReCaptchaEnterpriseProvider(
  environment.reCAPTCHAEnterpriseKey.key
  ),
  isTokenAutoRefreshEnabled: true,
  });
  if (location.hostname === 'localhost') {
    self.FIREBASE_APPCHECK_DEBUG_TOKEN = true;
  }
  return appCheck;
}),

如需允许本地测试,请将 self.FIREBASE_APPCHECK_DEBUG_TOKEN 设置为 true。当您在 localhost 中刷新应用时,系统会在控制台中记录一个调试令牌,类似于以下内容:

App Check debug token: CEFC0C76-7891-494B-B764-349BDFD00D00. You will need to add it to your app's App Check settings in the Firebase console for it to work.

现在,前往 Firebase 控制台中 App Check 的应用视图

点击溢出菜单,然后选择管理调试令牌

然后,点击添加调试令牌,并按照提示粘贴控制台中的调试令牌。

前往 chat.service.ts 文件,然后添加以下导入内容:

import { AppCheck } from '@angular/fire/app-check';

在同一 chat.service.ts 文件中,将 App Check 与其他 Firebase 服务一起注入。

export class ChatService {
appCheck: AppCheck = inject(AppCheck);
...
  1. 创建一个提交,并将提交消息设为“使用 App Check 屏蔽未经授权的客户端”,然后将其推送到您的 GitHub 代码库。
  2. 在 Firebase 控制台中打开 App Hosting 页面,然后等待新的发布完成。

恭喜!现在,您的应用应该可以正常运行 App Check 了。