AngularFire Web 代码实验室

1. 概述

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

angularfire-2.png

你将学到什么

  • 使用 Angular 和 Firebase 构建 Web 应用。
  • 使用 Cloud Firestore 和 Cloud Storage for Firebase 同步数据。
  • 使用 Firebase 身份验证对您的用户进行身份验证。
  • 在 Firebase 托管上部署您的 Web 应用。
  • 使用 Firebase 云消息传递发送通知。
  • 收集您的网络应用程序的性能数据。

你需要什么

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

2. 获取示例代码

从命令行克隆 Codelab 的GitHub 存储库

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

或者,如果您没有安装 git,则可以将存储库下载为 ZIP 文件

导入入门应用程序

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

3. 创建并设置 Firebase 项目

创建 Firebase 项目

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

您要构建的应用程序使用可用于网络应用的 Firebase 产品:

  • Firebase 身份验证可轻松允许您的用户登录您的应用。
  • Cloud Firestore将结构化数据保存在云上,并在数据发生变化时获得即时通知。
  • Cloud Storage for Firebase将文件保存在云中。
  • Firebase Hosting用于托管和服务您的资产。
  • Firebase Cloud Messaging用于发送推送通知并显示浏览器弹出通知。
  • Firebase 性能监控,用于收集应用的用户性能数据。

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

将 Firebase Web 应用添加到项目中

  1. 单击网络图标58d6543a156e56f9.png创建一个新的 Firebase Web 应用。
  2. 使用昵称“Friendly Chat”注册应用程序,然后选中“同时为此应用程序设置 Firebase 托管”旁边的框。单击注册应用程序
  3. 在下一步中,您将看到一个配置对象。仅将 JS 对象(而不是周围的 HTML)复制到firebase-config.js

注册网络应用程序截图

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

要允许用户使用其 Google 帐户登录网络应用程序,您将使用Google登录方法。

您需要启用Google登录:

  1. 在 Firebase 控制台中,找到左侧面板中的“构建”部分。
  2. 单击“身份验证” ,然后单击“登录方法”选项卡(或单击此处直接转到此处)。
  3. 启用Google登录提供商,然后单击“保存”
  4. 将应用程序面向公众的名称设置为“友好聊天” ,然后从下拉菜单中选择项目支持电子邮件
  5. Google Cloud Console中配置 OAuth 同意屏幕并添加徽标:

d89fb3873b5d36ae.png

启用 Cloud Firestore

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

您需要启用 Cloud Firestore:

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

729991a081e7cd5.png

  1. 选择“以测试模式启动”选项,然后在阅读有关安全规则的免责声明后单击“下一步”

测试模式保证您在开发过程中可以自由地写入数据库。稍后您将在此 Codelab 中使我们的数据库更加安全。

77e4986cbeaf9dee.png

  1. 设置 Cloud Firestore 数据的存储位置。您可以将其保留为默认值或选择离您较近的区域。单击“完成”以配置 Firestore。

9f2bb0d4e7ca49c7.png

启用云存储

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

您需要启用云存储:

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

使用默认安全规则,任何经过身份验证的用户都可以向 Cloud Storage 写入任何内容。稍后,您将在此 Codelab 中使我们的存储更加安全。

62f1afdcd1260127.png

  1. 预先选择的 Cloud Storage 位置与您为 Cloud Firestore 数据库选择的区域相同。单击“完成”完成设置。

1d7f49ebaddb32fc.png

4.安装Firebase命令行界面

Firebase 命令行界面 (CLI) 允许您使用 Firebase 托管在本地提供您的 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 托管配置。但要提取配置,您需要将应用程序与 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 托管模拟器在本地为我们的应用程序提供服务。现在应该可以从http://localhost:5000访问该 Web 应用程序。提供位于src子目录下的所有文件。

  1. 使用浏览器,在http://localhost:5000打开您的应用程序。

您应该会看到FriendlyChat应用程序的UI,它(尚未!)运行:

AngularFire-2.png

该应用程序现在无法执行任何操作,但在您的帮助下,很快就会!到目前为止,您只为您设计了 UI。

现在让我们建立一个实时聊天!

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",
    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 身份验证、Cloud Firestore、云存储、云消息传递和性能监控,因此您将导入它们的所有库。在您未来的应用中,请确保您仅导入所需的 Firebase 部分,以缩短应用的加载时间。

8. 设置用户登录

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

使用 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;
    })
}

当用户单击“注销”按钮时,会触发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);
    })
}

跟踪身份验证状态

要相应地更新我们的 UI,您需要一种方法来检查用户是否登录或注销。使用 Firebase 身份验证,您可以检索每次身份验证状态更改时将触发的用户状态的可观察值。

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

chat.service.ts

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

上面的代码调用 AngularFire 函数user ,它返回一个可观察的用户。每次身份验证状态更改时(当用户登录或注销时)都会触发它。此时,您将更新 UI 以进行重定向、在标题导航中显示用户等。所有这些 UI 部分都已实现。

测试登录应用程序

  1. 如果您的应用程序仍在运行,请在浏览器中刷新您的应用程序。否则,请在命令行上运行firebase emulators:start以开始从http://localhost:5000提供应用程序,然后在浏览器中打开它。
  2. 使用登录按钮和您的 Google 帐户登录该应用程序。如果您看到一条错误消息,指出auth/operation-not-allowed ,请检查以确保您在 Firebase 控制台中启用了 Google Sign-in 作为身份验证提供程序。
  3. 登录后,应显示您的个人资料图片和用户名: angularfire-3.png

9. 将消息写入 Cloud Firestore

在本部分中,您将向 Cloud Firestore 写入一些数据,以便填充应用的 UI。这可以使用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 控制台中看到新添加的消息。打开您的模拟器套件 UI。在“构建”部分下,单击Firestore 数据库(或单击此处,您应该会看到包含新添加消息的消息集合:

6812efe7da395692.png

10. 阅读消息

同步消息

要读取应用程序中的消息,您需要添加一个在数据更改时触发的可观察对象,然后创建一个显示新消息的 UI 元素。

您将添加代码来侦听来自应用程序的新添加的消息。在此代码中,您将检索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. 您之前在数据库中创建的消息应显示在FriendlyChat UI 中(见下文)。随意写新消息;它们应该立即出现。
  3. (可选)您可以尝试直接在模拟器套件的Firestore部分中手动删除、修改或添加新消息;任何更改都应反映在 UI 中。

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

AngularFire-2.png

11.发送图像

您现在将添加共享图像的功能。

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

将图像保存到云存储

在此 Codelab 中,您已经添加了一个可触发文件选择器对话框的按钮。选择文件后,将调用saveImageMessage函数,您可以获得对所选文件的引用。 saveImageMessage函数完成以下任务:

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

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

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

聊天服务.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. 应用程序的 UI 中应出现一条新消息,其中包含您选择的图像: AngularFire-2.png

如果您在未登录的情况下尝试添加图像,您应该会看到一条错误消息,告诉您必须登录才能添加图像。

12.显示通知

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

添加 FCM 服务工作人员

Web 应用程序需要一个Service Worker来接收和显示 Web 通知。

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

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

app/app.module.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. 如果您的应用程序仍在运行,请在浏览器中刷新您的应用程序。否则,请在命令行上运行firebase emulators:start以开始从http://localhost:5000提供应用程序,然后在浏览器中打开它。
  2. 登录后,应出现通知权限对话框: bd3454e6dbfb6723.png
  3. 单击“允许”
  4. 打开浏览器的 JavaScript 控制台。您应该看到以下消息: Got FCM device token: cWL6w:APA91bHP...4jDPL_A-wPP06GJp1OuekTaTZI5K2Tu
  5. 复制您的设备令牌。您将在 Codelab 的下一阶段需要它。

向您的设备发送通知

现在您已拥有设备令牌,您可以发送通知。

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

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

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

de79e8638a45864c.png

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_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 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

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

存储规则

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 托管部署您的应用

Firebase 提供托管服务来为您的资产和 Web 应用提供服务。您可以使用 Firebase CLI 将文件部署到 Firebase 托管。在部署之前,您需要在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. 访问您的 Web 应用程序,该应用程序现在已在您自己的两个 Firebase 子域中使用 Firebase 托管完全托管在全球 CDN 上:
  • https://<firebase-projectId>.firebaseapp.com
  • https://<firebase-projectId>.web.app

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

请访问文档以详细了解Firebase 托管的工作原理

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

15. 恭喜!

您已使用 Firebase 构建了实时聊天 Web 应用程序!

您所涵盖的内容

  • Firebase 身份验证
  • 云Firestore
  • 适用于云存储的 Firebase SDK
  • Firebase 云消息传递
  • Firebase 性能监控
  • Firebase 托管

下一步

了解更多

16. [可选] 通过应用程序检查强制执行

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

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

启用 reCaptcha Enterprise

  1. 在 Cloud 控制台中,找到并选择“安全性”下的reCaptcha Enterprise
  2. 根据提示启用服务,然后单击“创建密钥”
  3. 根据提示输入显示名称,平台类型选择“网站”
  4. 将您部署的 URL 添加到域列表中,并确保未选择“使用复选框质询”选项。
  5. 单击“创建密钥” ,并将生成的密钥存储在某处以妥善保管。您稍后将在此步骤中需要它。

启用应用程序检查

  1. 在 Firebase 控制台中,找到左侧面板中的“构建”部分。
  2. 单击App Check ,然后单击登录方法选项卡以导航至App Check
  3. 单击“注册”并在出现提示时输入您的 reCaptcha Enterprise 密钥,然后单击“保存”
  4. 在 API 视图中,选择存储并单击强制。对Cloud Firestore执行相同的操作。

现在应该强制执行应用程序检查!刷新您的应用程序并尝试查看或发送聊天消息。您应该收到错误消息:

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 现在应该可以在您的应用程序中运行。