AngularFire Web Codelab

1. 概览

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

角火 2.png

学习内容

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

所需条件

  • 您选择的 IDE/文本编辑器,例如 WebStormAtomSublimeVS Code
  • 软件包管理器 npm(通常随 Node.js 一起提供)
  • 终端/控制台
  • 您选择的浏览器(例如 Chrome)
  • 此 Codelab 的示例代码(请参阅此 Codelab 的下一步,了解如何获取代码。)

2. 获取示例代码

从命令行克隆此 Codelab 的 GitHub 代码库

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

或者,如果您未安装 git,则可以以 ZIP 文件的形式下载代码库

导入 starter 应用

使用 IDE 从克隆的代码库中打开或导入 📁? angularfire-start 目录。此 📁? angularfire-start 目录包含此 Codelab 的起始代码,它将是一个功能齐全的聊天 Web 应用。

3. 创建和设置 Firebase 项目

创建 Firebase 项目

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

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

  • Firebase Authentication:可让用户轻松登录您的应用。
  • Cloud Firestore:用于将结构化数据保存在云端,并在数据发生变化时获得即时通知。
  • Cloud Storage for Firebase:可用于将文件保存到云端。
  • Firebase Hosting:用于托管和提供您的资源。
  • Firebase Cloud Messaging:用于发送推送通知并显示浏览器弹出式通知。
  • Firebase Performance Monitoring 用于收集您的应用的用户性能数据。

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

将 Firebase Web 应用添加到项目中

  1. 点击 Web 图标 58d6543a156e56f9.png 以创建新的 Firebase Web 应用。
  2. 使用别名 Clear Chat 注册应用,然后选中 同时使用 Firebase Hosting for this app 旁边的复选框。点击 Register app
  3. 在下一步中,您将看到一个配置对象。仅将 JS 对象(而非周围的 HTML)复制到 firebase-config.js

注册 Web 应用的屏幕截图

启用 Google 登录功能以进行 Firebase 身份验证

如要允许用户使用其 Google 帐号登录 Web 应用,请使用 Google 登录方法。

您需要启用 Google 登录功能:

  1. 在 Firebase 控制台中,找到左侧面板中的构建部分。
  2. 点击身份验证,然后点击登录方法标签页(或点击此处直接转到相应页面)。
  3. 启用 Google 登录提供方,然后点击保存
  4. 将应用的公开名称设置为 Relation Chat,并从下拉菜单中选择 Project support email(项目支持电子邮件地址)。
  5. Google Cloud 控制台中配置 OAuth 权限请求页面,并添加徽标:

d89fb3873b5d36ae

启用 Cloud Firestore

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

您需要启用 Cloud Firestore:

  1. 在 Firebase 控制台的构建部分中,点击 Firestore 数据库
  2. 点击 Cloud Firestore 窗格中的创建数据库

729991a081e7cd5.png

  1. 选择以测试模式开始选项,然后在阅读有关安全规则的免责声明后点击下一步

测试模式可确保您在开发过程中可以随意向数据库写入数据。在此 Codelab 后面的内容中,您将提高数据库的安全性。

77e4986cbeaf9dee.png

  1. 设置 Cloud Firestore 数据的存储位置。你可以将其保留为默认值,或选择你附近的区域。点击完成以预配 Firestore。

9f2bb0d4e7ca49c7

启用 Cloud Storage

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

您需要启用 Cloud Storage:

  1. 在 Firebase 控制台的构建部分中,点击存储
  2. 如果没有开始使用按钮,则表示已启用 Cloud Storage,您无需按照以下步骤操作。
  3. 点击开始使用
  4. 阅读有关 Firebase 项目安全规则的免责声明,然后点击下一步

设置默认安全规则后,任何通过身份验证的用户都可以向 Cloud Storage 写入任何内容。在此 Codelab 后面的内容中,您将提高存储空间的安全性。

62f1afdcd1260127.png

  1. Cloud Storage 位置已预先选定,以及您为 Cloud Firestore 数据库选择的区域。点击完成以完成设置。

1d7f49ebaddb32fc.png

4.安装 Firebase 命令行界面

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

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

确保 Firebase CLI 版本为 v4.1.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. 出现提示时,选择在 Firebase 控制台中设置的功能(ng deploy -- hostingAuthenticationFirestoreCloud Functions (callable)Cloud MessagingCloud Storage),然后按照控制台上的提示操作。

6. 在本地运行起始应用

现在您已导入和配置项目,可以首次运行 Web 应用了。

  1. 在控制台中,从 angularfire-start 目录运行以下 Firebase CLI 命令:
firebase emulators:start
  1. 命令行应显示以下响应:
✔  hosting: Local server: http://localhost:5000

您在使用 Firebase Hosting 模拟器在本地提供我们的应用。Web 应用现在应该可以通过 http://localhost:5000 访问。位于 src 子目录下的所有文件都会传送。

  1. 使用浏览器,在 http://localhost:5000 上打开应用。

您应该会看到您的 FreeChat 应用的界面,它尚未正常运行:

角火 2.png

该应用程序目前无法执行任何操作,但在您的帮助下,它很快就会完成!到目前为止,您只布置了界面。

现在,我们来建立实时聊天!

7. 导入和配置 Firebase

配置 Firebase

您需要配置 Firebase SDK,以告知它您正在使用的 Firebase 项目。

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

您会发现系统为您生成了一个环境文件 /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",
    databaseURL: "https://PROJECT_ID.firebaseio.com",
    projectId: "PROJECT_ID",
    storageBucket: "PROJECT_ID.appspot.com",
    messagingSenderId: "SENDER_ID",
    appId: "APP_ID",
    measurementId: "G-MEASUREMENT_ID",
  },
};

导入 AngularFire

您会发现,您在控制台中选择的功能都是自动在 /angularfire-start/src/app/app.module.ts 文件中路由的。这样,您的应用就可以使用 Firebase 功能。不过,如需在本地环境中进行开发,您需要将其连接起来,才能使用模拟器套件。

  1. /angularfire-start/src/app/app.module.ts 中找到 imports 部分,并修改提供的函数以连接到非生产环境中的模拟器套件。
// ...

import { provideAuth,getAuth, connectAuthEmulator } from '@angular/fire/auth';
import { provideFirestore,getFirestore, connectFirestoreEmulator } from '@angular/fire/firestore';
import { provideFunctions,getFunctions, connectFunctionsEmulator } from '@angular/fire/functions';
import { provideMessaging,getMessaging } from '@angular/fire/messaging';
import { provideStorage,getStorage, connectStorageEmulator } from '@angular/fire/storage';

// ...

provideFirebaseApp(() => initializeApp(environment.firebase)),
provideAuth(() => {
    const auth = getAuth();
    if (location.hostname === 'localhost') {
        connectAuthEmulator(auth, 'http://127.0.0.1:9099', { disableWarnings: true });
    }
    return auth;
}),
provideFirestore(() => {
    const firestore = getFirestore();
    if (location.hostname === 'localhost') {
        connectFirestoreEmulator(firestore, '127.0.0.1', 8080);
    }
    return firestore;
}),
provideFunctions(() => {
    const functions = getFunctions();
    if (location.hostname === 'localhost') {
        connectFunctionsEmulator(functions, '127.0.0.1', 5001);
    }
    return functions;
}),
provideStorage(() => {
    const storage = getStorage();
    if (location.hostname === 'localhost') {
        connectStorageEmulator(storage, '127.0.0.1', 5001);
    }
    return storage;
}),
provideMessaging(() => {
    return getMessaging();
}),

// ...

app.module.ts

在此 Codelab 中,您将使用 Firebase Authentication、Cloud Firestore、Cloud Storage、Cloud Messaging 和 Performance Monitoring,因此您将导入它们的所有库。在以后的应用中,请确保您只导入所需的 Firebase 部分,以缩短应用的加载时间。

8. 设置用户登录

现在,AngularFire 应该已可供使用,因为它已在 app.module.ts 中导入并初始化。您现在将使用 Firebase Authentication 实现用户登录。

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

在应用中,当用户点击 Sign in with Google(使用 Google 帐号登录)按钮时,会触发 login 函数。(您已经进行了相应设置!)对于此 Codelab,您需要授权 Firebase 使用 Google 作为身份提供方。您将使用弹出式窗口,不过 Firebase 中也提供了多种其他方法

  1. angularfire-start 目录下的 /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;
    })
}

当用户点击 Log out 按钮时,就会触发 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);
    })
}

跟踪身份验证状态

如需相应地更新界面,您需要一种方法来检查用户是处于登录状态还是已退出登录状态。借助 Firebase Authentication,您可以检索用户状态的可观测数据,每当身份验证状态发生变化时触发。

  1. 返回至 src/app/services/chat.service.ts 文件。
  2. 找到变量赋值 user$
  3. 将整个赋值替换为以下代码。

chat.service.ts

// Observable user
user$ = user(this.auth);

上述代码会调用 AngularFire 函数 user,后者会返回一个可观察用户。每当身份验证状态发生变化时(当用户登录或退出帐号时),它就会触发。此时,您将更新界面以重定向、在标头导航中显示用户,以及执行其他操作。所有这些界面部分均已实现。

测试登录应用

  1. 如果您的应用仍在提供,请在浏览器中刷新您的应用。否则,请在命令行上运行 firebase emulators:start,开始通过 http://localhost:5000 提供应用,然后在浏览器中打开该应用。
  2. 使用登录按钮和您的 Google 帐号登录该应用。如果您看到错误消息“auth/operation-not-allowed”,请检查是否已在 Firebase 控制台中启用 Google 登录作为身份验证提供方。
  3. 登录后,系统应该会显示您的个人资料照片和用户名:Angularfire-3.png

9. 向 Cloud Firestore 写入消息

在本部分中,您会将一些数据写入 Cloud Firestore,以便填充应用的界面。此操作可以使用 Firebase 控制台手动完成,但为了演示基本的 Cloud Firestore 写入,您需要在应用本身中执行。

数据模型

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

688d7bc5fb662b57.png

向 Cloud Firestore 添加消息

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

在本部分中,您将为用户添加向数据库写入新消息的功能。用户点击发送按钮会触发以下代码段。它会将一个包含消息字段内容的消息对象添加到 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>> => {
    let data: any;
    try {
      this.user$.subscribe(async (user) => 
      { 
        if(textMessage && textMessage.length > 0) {
          data =  await addDoc(collection(this.firestore, 'messages'), {
            name: user?.displayName,
            text: textMessage,
            profilePicUrl: user?.photoURL,
            timestamp: serverTimestamp(),
            uid: user?.uid
          })}
          else if (imageUrl && imageUrl.length > 0) {
            data =  await addDoc(collection(this.firestore, 'messages'), {
              name: user?.displayName,
              imageUrl: imageUrl,
              profilePicUrl: user?.photoURL,
              timestamp: serverTimestamp(),
              uid: user?.uid
            });
          }
          return data;
        }
      );
    }
    catch(error) {
      console.error('Error writing new message to Firebase Database', error);
      return;
    }
}

测试发送消息

  1. 如果您的应用仍在提供,请在浏览器中刷新您的应用。否则,请在命令行上运行 firebase emulators:start,开始通过 http://localhost:5000 提供应用,然后在浏览器中打开该应用。
  2. 登录后,输入“嗨!”等消息,然后点击发送。这会将消息写入 Cloud Firestore。不过,您尚无法在实际 Web 应用中看到数据,因为您仍需实现数据检索功能(此 Codelab 的下一部分)。
  3. 您可以在 Firebase 控制台中查看新添加的消息。打开模拟器套件界面。在构建部分下,点击 Firestore 数据库(或点击此处,您应该会看到包含新添加消息的 messages 集合:

6812efe7da395692

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. 如果您的应用仍在提供,请在浏览器中刷新您的应用。否则,请在命令行上运行 firebase emulators:start,开始通过 http://localhost:5000 提供应用,然后在浏览器中打开该应用。
  2. 您之前在数据库中创建的消息应显示在 RelationChat 界面中(见下文)。您可以随意撰写新消息,这些消息应该会立即显示。
  3. (可选)您可以尝试直接在模拟器套件的 Firestore 部分中手动删除、修改或添加新消息;所有更改都应反映在界面中。

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

角火 2.png

11. 发送图片

您现在将添加分享图片的功能。

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

将图片保存到 Cloud Storage

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

  1. 在聊天信息流中创建“占位符”聊天消息,以便用户在您上传图片时看到“正在加载”动画。
  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 Firebase.
// This first saves the image in Firebase storage.
saveImageMessage = async(file: any) => {
  try {
    // 1 - You 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. 如果您的应用仍在提供,请在浏览器中刷新您的应用。否则,请在命令行上运行 firebase emulators:start,开始通过 http://localhost:5000 提供应用,然后在浏览器中打开该应用。
  2. 登录后,点击左下角的图片上传按钮 Angularfire-4.png,然后使用文件选择器选择一个图片文件。如果您正在寻找图片,可以随时使用这张精美的咖啡杯图片
  3. 应用的界面中应会显示一条新消息以及您选择的图片:角火 2.png

如果您在未登录的情况下尝试添加图片,将会看到一条错误消息,提示您必须登录才能添加图片。

12. 显示通知

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

添加 FCM Service Worker

Web 应用需要一个可接收并显示网络通知的 Service Worker

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

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

app/app.module.ts

Service Worker 只需加载并初始化 Firebase Cloud Messaging SDK,此 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. 如果您的应用仍在提供,请在浏览器中刷新您的应用。否则,请在命令行上运行 firebase emulators:start,开始通过 http://localhost:5000 提供应用,然后在浏览器中打开该应用。
  2. 登录后,您应该会看到通知权限对话框:bd3454e6dbfb6723
  3. 点击允许
  4. 打开浏览器的 JavaScript 控制台。您应该会看到以下消息:Got FCM device token: cWL6w:APA91bHP...4jDPL_A-wPP06GJp1OuekTaTZI5K2Tu
  5. 复制您的设备令牌。在本 Codelab 的下一阶段,将会用到它。

向您的设备发送通知

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

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

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

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

de79e8638a45864c

13. 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 安全规则

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

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

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;
    }
  }
}

14. 使用 Firebase Hosting 部署应用

Firebase 提供托管服务来传送您的资源和 Web 应用。您可以使用 Firebase CLI 将文件部署到 Firebase Hosting。在部署之前,您需要在 firebase.json 文件中指定应部署哪些本地文件。对于此 Codelab,您已经完成了此步骤,因为在此 Codelab 期间,必须执行此步骤来处理我们的文件。托管设置在 hosting 属性下指定:

firebase.json

{
  // If you went through the "Cloud Firestore Security Rules" step.
  "firestore": {
    "rules": "firestore.rules"
  },
  // If you went through the "Storage Security Rules" step.
  "storage": {
    "rules": "storage.rules"
  },
  "hosting": {
    "public": "./public"
  }
}

这些设置会告知 CLI,您要部署 ./public 目录 ( "public": "./public") 中的所有文件。

  1. 确保您的命令行可以访问应用的本地 angularfire-start 目录。
  2. 运行以下命令,将您的文件部署到 Firebase 项目:
ng deploy

然后选择 Firebase 选项,并按照命令行中的提示操作。

  1. 控制台应显示以下内容:
=== Deploying to 'friendlychat-1234'...

i  deploying firestore, storage, hosting
i  storage: checking storage.rules for compilation errors...
✔  storage: rules file storage.rules compiled successfully
i  firestore: checking firestore.rules for compilation errors...
✔  firestore: rules file firestore.rules compiled successfully
i  storage: uploading rules storage.rules...
i  firestore: uploading rules firestore.rules...
i  hosting[friendlychat-1234]: beginning deploy...
i  hosting[friendlychat-1234]: found 8 files in ./public
✔  hosting[friendlychat-1234]: file upload complete
✔  storage: released rules storage.rules to firebase.storage/friendlychat-1234.appspot.com
✔  firestore: released rules firestore.rules to cloud.firestore
i  hosting[friendlychat-1234]: finalizing version...
✔  hosting[friendlychat-1234]: version finalized
i  hosting[friendlychat-1234]: releasing new version...
✔  hosting[friendlychat-1234]: release complete

✔  Deploy complete!

Project Console: https://console.firebase.google.com/project/friendlychat-1234/overview
Hosting URL: https://friendlychat-1234.firebaseapp.com
  1. 使用您自己的两个 Firebase 子网域上的 Firebase Hosting 访问现在完全托管在全球 CDN 上的 Web 应用:
  • https://<firebase-projectId>.firebaseapp.com
  • https://<firebase-projectId>.web.app

或者,您也可以在命令行中运行 firebase open hosting:site

如需详细了解 Firebase Hosting 的工作原理,请访问相关文档。

您可以前往项目的 Firebase 控制台托管部分,查看有用的托管信息和工具,包括部署历史记录、回滚到旧版应用的功能以及设置自定义网域的工作流。

15. 恭喜!

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

所学内容

  • Firebase Authentication
  • Cloud Firestore
  • 适用于 Cloud Storage 的 Firebase SDK
  • Firebase Cloud Messaging
  • Firebase Performance Monitoring
  • Firebase Hosting

后续步骤

了解详情

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.appspot.com',
    messagingSenderId: 'SENDER_ID',
    appId: 'APP_ID',
    measurementId: 'G-MEASUREMENT_ID',
  },
  reCAPTCHAEnterpriseKey: {
    key: "Replace with your recaptcha enterprise site key"
  },
};

key 的值替换为您的 reCAPTCHA Enterprise 令牌。

然后,找到 app.module.ts 文件并添加以下导入内容:

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

在同一 app.module.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);
...

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