Lớp học lập trình web Cloud Firestore

1. Khái quát chung

Bàn thắng

Trong lớp học lập trình này, bạn sẽ xây dựng một ứng dụng web đề xuất nhà hàng được hỗ trợ bởi Cloud Firestore .

img5.png

Bạn sẽ học được gì

  • Đọc và ghi dữ liệu vào Cloud Firestore từ ứng dụng web
  • Lắng nghe những thay đổi trong dữ liệu Cloud Firestore trong thời gian thực
  • Sử dụng các quy tắc bảo mật và xác thực Firebase để bảo mật dữ liệu Cloud Firestore
  • Viết các truy vấn Cloud Firestore phức tạp

Những gì bạn cần

Trước khi bắt đầu lớp học lập trình này, hãy đảm bảo rằng bạn đã cài đặt:

  • npm thường đi kèm với Node.js - Nên sử dụng Node 16+
  • IDE/trình soạn thảo văn bản bạn chọn, chẳng hạn như WebStorm , VS Code hoặc Sublime

2. Tạo và thiết lập dự án Firebase

Tạo dự án Firebase

  1. Trong bảng điều khiển Firebase , hãy nhấp vào Thêm dự án , sau đó đặt tên cho dự án Firebase là FriendlyEats .

Hãy nhớ ID dự án cho dự án Firebase của bạn.

  1. Nhấp vào Tạo dự án .

Ứng dụng mà chúng ta sắp xây dựng sử dụng một số dịch vụ Firebase có sẵn trên web:

  • Xác thực Firebase để dễ dàng xác định người dùng của bạn
  • Cloud Firestore để lưu dữ liệu có cấu trúc trên Đám mây và nhận thông báo ngay lập tức khi dữ liệu được cập nhật
  • Firebase Hosting để lưu trữ và phục vụ nội dung tĩnh của bạn

Đối với lớp học lập trình cụ thể này, chúng tôi đã định cấu hình Dịch vụ lưu trữ Firebase. Tuy nhiên, đối với Firebase Auth và Cloud Firestore, chúng tôi sẽ hướng dẫn bạn cách định cấu hình và kích hoạt các dịch vụ bằng bảng điều khiển Firebase.

Bật xác thực ẩn danh

Mặc dù xác thực không phải là trọng tâm của lớp học lập trình này nhưng điều quan trọng là phải có một số hình thức xác thực trong ứng dụng của chúng ta. Chúng tôi sẽ sử dụng thông tin đăng nhập Ẩn danh - nghĩa là người dùng sẽ đăng nhập một cách im lặng mà không được nhắc.

Bạn sẽ cần kích hoạt đăng nhập ẩn danh.

  1. Trong bảng điều khiển Firebase, tìm phần Xây dựng ở điều hướng bên trái.
  2. Nhấp vào Xác thực , sau đó nhấp vào tab Phương thức đăng nhập (hoặc nhấp vào đây để truy cập trực tiếp vào đó).
  3. Kích hoạt Nhà cung cấp đăng nhập ẩn danh , sau đó nhấp vào Lưu .

img7.png

Điều này sẽ cho phép ứng dụng đăng nhập âm thầm vào người dùng của bạn khi họ truy cập ứng dụng web. Vui lòng đọc tài liệu Xác thực ẩn danh để tìm hiểu thêm.

Kích hoạt Cloud Firestore

Ứng dụng sử dụng Cloud Firestore để lưu và nhận thông tin cũng như xếp hạng nhà hàng.

Bạn sẽ cần kích hoạt Cloud Firestore. Trong phần Build của bảng điều khiển Firebase, nhấp vào Cơ sở dữ liệu Firestore . Nhấp vào Tạo cơ sở dữ liệu trong ngăn Cloud Firestore.

Quyền truy cập vào dữ liệu trong Cloud Firestore được kiểm soát bởi Quy tắc bảo mật. Chúng ta sẽ nói nhiều hơn về các quy tắc sau trong lớp học lập trình này nhưng trước tiên chúng ta cần đặt một số quy tắc cơ bản về dữ liệu của mình để bắt đầu. Trong tab Quy tắc của bảng điều khiển Firebase, hãy thêm các quy tắc sau rồi nhấp vào Xuất bản .

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      //
      // WARNING: These rules are insecure! We will replace them with
      // more secure rules later in the codelab
      //
      allow read, write: if request.auth != null;
    }
  }
}

Các quy tắc ở trên hạn chế quyền truy cập dữ liệu đối với người dùng đã đăng nhập, điều này ngăn người dùng chưa được xác thực đọc hoặc viết. Điều này tốt hơn việc cho phép truy cập công khai nhưng vẫn chưa đảm bảo an toàn, chúng tôi sẽ cải thiện các quy tắc này sau trong lớp học lập trình.

3. Lấy mã mẫu

Sao chép kho GitHub từ dòng lệnh:

git clone https://github.com/firebase/friendlyeats-web

Mã mẫu đáng lẽ phải được sao chép vào thư mục 📁 friendlyeats-web . Từ giờ trở đi, hãy đảm bảo chạy tất cả các lệnh của bạn từ thư mục này:

cd friendlyeats-web/vanilla-js

Nhập ứng dụng khởi đầu

Sử dụng IDE của bạn (WebStorm, Atom, Sublime, Visual Studio Code...) để mở hoặc nhập thư mục 📁 friendlyeats-web . Thư mục này chứa mã bắt đầu cho lớp học lập trình, bao gồm một ứng dụng đề xuất nhà hàng chưa hoạt động. Chúng tôi sẽ làm cho nó hoạt động trong suốt lớp học lập trình này nên bạn sẽ cần sớm chỉnh sửa mã trong thư mục đó.

4. Cài đặt giao diện dòng lệnh Firebase

Giao diện dòng lệnh Firebase (CLI) cho phép bạn phân phát ứng dụng web cục bộ và triển khai ứng dụng web của mình lên Firebase Hosting.

  1. Cài đặt CLI bằng cách chạy lệnh npm sau:
npm -g install firebase-tools
  1. Xác minh rằng CLI đã được cài đặt chính xác bằng cách chạy lệnh sau:
firebase --version

Đảm bảo phiên bản Firebase CLI là v7.4.0 trở lên.

  1. Cho phép Firebase CLI bằng cách chạy lệnh sau:
firebase login

Chúng tôi đã thiết lập mẫu ứng dụng web để lấy cấu hình ứng dụng của bạn cho Dịch vụ lưu trữ Firebase từ thư mục và tệp cục bộ của ứng dụng. Nhưng để làm được điều này, chúng tôi cần liên kết ứng dụng của bạn với dự án Firebase.

  1. Đảm bảo rằng dòng lệnh của bạn đang truy cập vào thư mục cục bộ của ứng dụng.
  2. Liên kết ứng dụng của bạn với dự án Firebase bằng cách chạy lệnh sau:
firebase use --add
  1. Khi được nhắc, hãy chọn ID dự án của bạn, sau đó đặt bí danh cho dự án Firebase của bạn.

Bí danh rất hữu ích nếu bạn có nhiều môi trường (sản xuất, dàn dựng, v.v.). Tuy nhiên, đối với lớp học lập trình này, chúng ta hãy chỉ sử dụng bí danh default .

  1. Thực hiện theo các hướng dẫn còn lại trong dòng lệnh của bạn.

5. Chạy máy chủ cục bộ

Chúng tôi đã sẵn sàng thực sự bắt đầu công việc trên ứng dụng của mình! Hãy chạy ứng dụng của chúng tôi tại địa phương!

  1. Chạy lệnh Firebase CLI sau:
firebase emulators:start --only hosting
  1. Dòng lệnh của bạn sẽ hiển thị phản hồi sau:
hosting: Local server: http://localhost:5000

Chúng tôi đang sử dụng trình mô phỏng Firebase Hosting để phân phối ứng dụng của mình cục bộ. Ứng dụng web hiện có sẵn từ http://localhost:5000 .

  1. Mở ứng dụng của bạn tại http://localhost:5000 .

Bạn sẽ thấy bản sao FriendlyEats đã được kết nối với dự án Firebase của bạn.

Ứng dụng đã tự động kết nối với dự án Firebase của bạn và âm thầm đăng nhập cho bạn với tư cách người dùng ẩn danh.

img2.png

6. Ghi dữ liệu lên Cloud Firestore

Trong phần này, chúng tôi sẽ ghi một số dữ liệu vào Cloud Firestore để có thể đưa vào giao diện người dùng của ứng dụng. Việc này có thể được thực hiện thủ công thông qua bảng điều khiển Firebase nhưng chúng tôi sẽ thực hiện việc đó trong chính ứng dụng để minh họa cách ghi cơ bản trên Cloud Firestore.

Mô hình dữ liệu

Dữ liệu Firestore được chia thành các bộ sưu tập, tài liệu, trường và bộ sưu tập con. Chúng tôi sẽ lưu trữ mỗi nhà hàng dưới dạng tài liệu trong bộ sưu tập cấp cao nhất được gọi là restaurants .

img3.png

Sau đó, chúng tôi sẽ lưu trữ từng đánh giá trong một bộ sưu tập con được gọi là ratings theo từng nhà hàng.

img4.png

Thêm nhà hàng vào Firestore

Đối tượng mô hình chính trong ứng dụng của chúng tôi là một nhà hàng. Hãy viết một số mã để thêm tài liệu về nhà hàng vào bộ sưu tập restaurants .

  1. Từ các tệp đã tải xuống của bạn, hãy mở scripts/FriendlyEats.Data.js .
  2. Tìm hàm FriendlyEats.prototype.addRestaurant .
  3. Thay thế toàn bộ chức năng bằng đoạn mã sau.

FriendlyEats.Data.js

FriendlyEats.prototype.addRestaurant = function(data) {
  var collection = firebase.firestore().collection('restaurants');
  return collection.add(data);
};

Đoạn mã trên thêm một tài liệu mới vào bộ sưu tập restaurants . Dữ liệu tài liệu đến từ một đối tượng JavaScript đơn giản. Trước tiên, chúng tôi thực hiện việc này bằng cách lấy tham chiếu đến restaurants trong bộ sưu tập Cloud Firestore, sau đó add dữ liệu.

Hãy thêm nhà hàng!

  1. Quay lại ứng dụng FriendlyEats trong trình duyệt của bạn và làm mới nó.
  2. Nhấp vào Thêm dữ liệu mô phỏng .

Ứng dụng sẽ tự động tạo một tập hợp ngẫu nhiên các đối tượng nhà hàng, sau đó gọi hàm addRestaurant của bạn. Tuy nhiên, bạn sẽ chưa thấy dữ liệu trong ứng dụng web thực tế của mình vì chúng ta vẫn cần triển khai truy xuất dữ liệu (phần tiếp theo của lớp học lập trình).

Tuy nhiên, nếu bạn điều hướng đến tab Cloud Firestore trong bảng điều khiển Firebase, bây giờ bạn sẽ thấy các tài liệu mới trong bộ sưu tập restaurants !

img6.png

Xin chúc mừng, bạn vừa ghi dữ liệu vào Cloud Firestore từ một ứng dụng web!

Trong phần tiếp theo, bạn sẽ tìm hiểu cách truy xuất dữ liệu từ Cloud Firestore và hiển thị dữ liệu đó trong ứng dụng của mình.

7. Hiển thị dữ liệu từ Cloud Firestore

Trong phần này, bạn sẽ tìm hiểu cách truy xuất dữ liệu từ Cloud Firestore và hiển thị dữ liệu đó trong ứng dụng của mình. Hai bước chính là tạo truy vấn và thêm trình nghe ảnh chụp nhanh. Người nghe này sẽ được thông báo về tất cả dữ liệu hiện có phù hợp với truy vấn và sẽ nhận được thông tin cập nhật theo thời gian thực.

Trước tiên, hãy xây dựng truy vấn sẽ phục vụ danh sách nhà hàng mặc định, chưa được lọc.

  1. Quay lại tập tin scripts/FriendlyEats.Data.js .
  2. Tìm hàm FriendlyEats.prototype.getAllRestaurants .
  3. Thay thế toàn bộ chức năng bằng đoạn mã sau.

FriendlyEats.Data.js

FriendlyEats.prototype.getAllRestaurants = function(renderer) {
  var query = firebase.firestore()
      .collection('restaurants')
      .orderBy('avgRating', 'desc')
      .limit(50);

  this.getDocumentsInQuery(query, renderer);
};

Trong đoạn mã trên, chúng tôi xây dựng một truy vấn sẽ truy xuất tối đa 50 nhà hàng từ bộ sưu tập cấp cao nhất có tên restaurants , được sắp xếp theo xếp hạng trung bình (hiện tại tất cả đều bằng 0). Sau khi khai báo truy vấn này, chúng ta chuyển nó sang phương thức getDocumentsInQuery() chịu trách nhiệm tải và hiển thị dữ liệu.

Chúng tôi sẽ thực hiện việc này bằng cách thêm trình nghe ảnh chụp nhanh.

  1. Quay lại tập tin scripts/FriendlyEats.Data.js .
  2. Tìm hàm FriendlyEats.prototype.getDocumentsInQuery .
  3. Thay thế toàn bộ chức năng bằng đoạn mã sau.

FriendlyEats.Data.js

FriendlyEats.prototype.getDocumentsInQuery = function(query, renderer) {
  query.onSnapshot(function(snapshot) {
    if (!snapshot.size) return renderer.empty(); // Display "There are no restaurants".

    snapshot.docChanges().forEach(function(change) {
      if (change.type === 'removed') {
        renderer.remove(change.doc);
      } else {
        renderer.display(change.doc);
      }
    });
  });
};

Trong đoạn mã trên, query.onSnapshot sẽ kích hoạt lệnh gọi lại mỗi khi có thay đổi đối với kết quả của truy vấn.

  • Lần đầu tiên, lệnh gọi lại được kích hoạt với toàn bộ tập kết quả của truy vấn – nghĩa là toàn bộ bộ sưu tập restaurants từ Cloud Firestore. Sau đó, nó chuyển tất cả các tài liệu riêng lẻ tới hàm renderer.display .
  • Khi một tài liệu bị xóa, change.type bằng với removed . Vì vậy, trong trường hợp này, chúng ta sẽ gọi một hàm để xóa nhà hàng khỏi giao diện người dùng.

Bây giờ chúng ta đã triển khai cả hai phương pháp, hãy làm mới ứng dụng và xác minh rằng các nhà hàng mà chúng ta thấy trước đó trong bảng điều khiển Firebase hiện đã hiển thị trong ứng dụng. Nếu bạn đã hoàn thành phần này thành công thì ứng dụng của bạn hiện đang đọc và ghi dữ liệu bằng Cloud Firestore!

Khi danh sách nhà hàng của bạn thay đổi, trình nghe này sẽ tự động cập nhật. Hãy thử truy cập bảng điều khiển Firebase và xóa nhà hàng hoặc đổi tên theo cách thủ công - bạn sẽ thấy các thay đổi hiển thị trên trang web của mình ngay lập tức!

img5.png

8. Lấy dữ liệu()

Cho đến nay, chúng tôi đã trình bày cách sử dụng onSnapshot để truy xuất các bản cập nhật trong thời gian thực; tuy nhiên, đó không phải lúc nào cũng là điều chúng ta mong muốn. Đôi khi sẽ hợp lý hơn nếu chỉ tìm nạp dữ liệu một lần.

Chúng tôi muốn triển khai một phương thức được kích hoạt khi người dùng nhấp vào một nhà hàng cụ thể trong ứng dụng của bạn.

  1. Quay lại tập tin scripts/FriendlyEats.Data.js của bạn.
  2. Tìm hàm FriendlyEats.prototype.getRestaurant .
  3. Thay thế toàn bộ chức năng bằng đoạn mã sau.

FriendlyEats.Data.js

FriendlyEats.prototype.getRestaurant = function(id) {
  return firebase.firestore().collection('restaurants').doc(id).get();
};

Sau khi triển khai phương pháp này, bạn sẽ có thể xem các trang của từng nhà hàng. Chỉ cần nhấp vào một nhà hàng trong danh sách và bạn sẽ thấy trang chi tiết của nhà hàng:

img1.png

Hiện tại, bạn không thể thêm xếp hạng vì chúng tôi vẫn cần triển khai việc thêm xếp hạng sau này trong lớp học lập trình.

9. Sắp xếp và lọc dữ liệu

Hiện tại, ứng dụng của chúng tôi hiển thị danh sách các nhà hàng nhưng không có cách nào để người dùng lọc dựa trên nhu cầu của họ. Trong phần này, bạn sẽ sử dụng truy vấn nâng cao của Cloud Firestore để bật tính năng lọc.

Dưới đây là ví dụ về truy vấn đơn giản để tìm nạp tất cả các nhà hàng Dim Sum :

var filteredQuery = query.where('category', '==', 'Dim Sum')

Đúng như tên gọi của nó, phương thức where() sẽ khiến truy vấn của chúng ta chỉ tải xuống các thành viên của bộ sưu tập có các trường đáp ứng các hạn chế mà chúng ta đặt ra. Trong trường hợp này, nó sẽ chỉ tải xuống những nhà hàng có categoryDim Sum .

Trong ứng dụng của chúng tôi, người dùng có thể xâu chuỗi nhiều bộ lọc để tạo các truy vấn cụ thể, như "Pizza ở San Francisco" hoặc "Hải sản ở Los Angeles đặt hàng theo mức độ phổ biến".

Chúng tôi sẽ tạo một phương pháp xây dựng truy vấn để lọc các nhà hàng của chúng tôi dựa trên nhiều tiêu chí do người dùng của chúng tôi chọn.

  1. Quay lại tập tin scripts/FriendlyEats.Data.js của bạn.
  2. Tìm hàm FriendlyEats.prototype.getFilteredRestaurants .
  3. Thay thế toàn bộ chức năng bằng đoạn mã sau.

FriendlyEats.Data.js

FriendlyEats.prototype.getFilteredRestaurants = function(filters, renderer) {
  var query = firebase.firestore().collection('restaurants');

  if (filters.category !== 'Any') {
    query = query.where('category', '==', filters.category);
  }

  if (filters.city !== 'Any') {
    query = query.where('city', '==', filters.city);
  }

  if (filters.price !== 'Any') {
    query = query.where('price', '==', filters.price.length);
  }

  if (filters.sort === 'Rating') {
    query = query.orderBy('avgRating', 'desc');
  } else if (filters.sort === 'Reviews') {
    query = query.orderBy('numRatings', 'desc');
  }

  this.getDocumentsInQuery(query, renderer);
};

Đoạn mã trên thêm nhiều bộ lọc where và một mệnh đề orderBy để xây dựng một truy vấn phức hợp dựa trên dữ liệu đầu vào của người dùng. Truy vấn của chúng tôi bây giờ sẽ chỉ trả về những nhà hàng phù hợp với yêu cầu của người dùng.

Làm mới ứng dụng FriendlyEats trong trình duyệt của bạn, sau đó xác minh rằng bạn có thể lọc theo giá, thành phố và danh mục. Trong khi kiểm tra, bạn sẽ thấy các lỗi trong Bảng điều khiển JavaScript của trình duyệt giống như sau:

The query requires an index. You can create it here: https://console.firebase.google.com/project/project-id/database/firestore/indexes?create_composite=...

Những lỗi này là do Cloud Firestore yêu cầu lập chỉ mục cho hầu hết các truy vấn phức hợp. Yêu cầu lập chỉ mục trên các truy vấn giúp Cloud Firestore có tốc độ nhanh trên quy mô lớn.

Việc mở liên kết từ thông báo lỗi sẽ tự động mở giao diện người dùng tạo chỉ mục trong bảng điều khiển Firebase với các tham số chính xác được điền vào. Trong phần tiếp theo, chúng ta sẽ viết và triển khai các chỉ mục cần thiết cho ứng dụng này.

10. Triển khai các chỉ mục

Nếu không muốn khám phá mọi đường dẫn trong ứng dụng của mình và đi theo từng liên kết tạo chỉ mục, chúng ta có thể dễ dàng triển khai nhiều chỉ mục cùng một lúc bằng cách sử dụng Firebase CLI.

  1. Trong thư mục cục bộ đã tải xuống của ứng dụng, bạn sẽ tìm thấy tệp firestore.indexes.json .

Tệp này mô tả tất cả các chỉ mục cần thiết cho tất cả các kết hợp bộ lọc có thể có.

firestore.indexes.json

{
 "indexes": [
   {
     "collectionGroup": "restaurants",
     "queryScope": "COLLECTION",
     "fields": [
       { "fieldPath": "city", "order": "ASCENDING" },
       { "fieldPath": "avgRating", "order": "DESCENDING" }
     ]
   },

   ...

 ]
}
  1. Triển khai các chỉ mục này bằng lệnh sau:
firebase deploy --only firestore:indexes

Sau vài phút, các chỉ mục của bạn sẽ hoạt động và các thông báo lỗi sẽ biến mất.

11. Ghi dữ liệu vào giao dịch

Trong phần này, chúng tôi sẽ thêm khả năng người dùng gửi đánh giá cho nhà hàng. Cho đến nay, tất cả các bài viết của chúng tôi đều rất đơn giản và tương đối đơn giản. Nếu bất kỳ lỗi nào trong số đó bị lỗi, chúng tôi có thể chỉ nhắc người dùng thử lại hoặc ứng dụng của chúng tôi sẽ tự động thử ghi lại.

Ứng dụng của chúng tôi sẽ có nhiều người dùng muốn thêm xếp hạng cho một nhà hàng, vì vậy chúng tôi sẽ cần phối hợp nhiều lần đọc và viết. Đầu tiên, bản đánh giá phải được gửi, sau đó count xếp hạng và average rating của nhà hàng cần được cập nhật. Nếu một trong những điều này không thành công nhưng điều kia thì không, thì chúng ta sẽ rơi vào trạng thái không nhất quán trong đó dữ liệu trong một phần cơ sở dữ liệu của chúng ta không khớp với dữ liệu trong phần khác.

May mắn thay, Cloud Firestore cung cấp chức năng giao dịch cho phép chúng tôi thực hiện nhiều lần đọc và ghi trong một thao tác nguyên tử duy nhất, đảm bảo rằng dữ liệu của chúng tôi luôn nhất quán.

  1. Quay lại tập tin scripts/FriendlyEats.Data.js của bạn.
  2. Tìm hàm FriendlyEats.prototype.addRating .
  3. Thay thế toàn bộ chức năng bằng đoạn mã sau.

FriendlyEats.Data.js

FriendlyEats.prototype.addRating = function(restaurantID, rating) {
  var collection = firebase.firestore().collection('restaurants');
  var document = collection.doc(restaurantID);
  var newRatingDocument = document.collection('ratings').doc();

  return firebase.firestore().runTransaction(function(transaction) {
    return transaction.get(document).then(function(doc) {
      var data = doc.data();

      var newAverage =
          (data.numRatings * data.avgRating + rating.rating) /
          (data.numRatings + 1);

      transaction.update(document, {
        numRatings: data.numRatings + 1,
        avgRating: newAverage
      });
      return transaction.set(newRatingDocument, rating);
    });
  });
};

Trong khối ở trên, chúng tôi kích hoạt một giao dịch để cập nhật các giá trị số của avgRatingnumRatings trong tài liệu nhà hàng. Đồng thời, chúng tôi thêm rating mới vào bộ sưu tập con ratings .

12. Bảo mật dữ liệu của bạn

Khi bắt đầu lớp học lập trình này, chúng tôi đặt các quy tắc bảo mật cho ứng dụng của mình để mở hoàn toàn cơ sở dữ liệu cho mọi thao tác đọc hoặc ghi. Trong một ứng dụng thực tế, chúng tôi muốn đặt ra các quy tắc chi tiết hơn nhiều để ngăn chặn việc truy cập hoặc sửa đổi dữ liệu không mong muốn.

  1. Trong phần Build của bảng điều khiển Firebase, nhấp vào Cơ sở dữ liệu Firestore .
  2. Nhấp vào tab Quy tắc trong phần Cloud Firestore (hoặc nhấp vào đây để truy cập trực tiếp vào đó).
  3. Thay thế các giá trị mặc định bằng các quy tắc sau, sau đó nhấp vào Xuất bản .

firestore.rules

rules_version = '2';
service cloud.firestore {

  // Determine if the value of the field "key" is the same
  // before and after the request.
  function unchanged(key) {
    return (key in resource.data) 
      && (key in request.resource.data) 
      && (resource.data[key] == request.resource.data[key]);
  }

  match /databases/{database}/documents {
    // Restaurants:
    //   - Authenticated user can read
    //   - Authenticated user can create/update (for demo purposes only)
    //   - Updates are allowed if no fields are added and name is unchanged
    //   - Deletes are not allowed (default)
    match /restaurants/{restaurantId} {
      allow read: if request.auth != null;
      allow create: if request.auth != null;
      allow update: if request.auth != null
                    && (request.resource.data.keys() == resource.data.keys()) 
                    && unchanged("name");
      
      // Ratings:
      //   - Authenticated user can read
      //   - Authenticated user can create if userId matches
      //   - Deletes and updates are not allowed (default)
      match /ratings/{ratingId} {
        allow read: if request.auth != null;
        allow create: if request.auth != null
                      && request.resource.data.userId == request.auth.uid;
      }
    }
  }
}

Các quy tắc này hạn chế quyền truy cập để đảm bảo rằng khách hàng chỉ thực hiện các thay đổi an toàn. Ví dụ:

  • Cập nhật tài liệu về nhà hàng chỉ có thể thay đổi xếp hạng chứ không phải tên hoặc bất kỳ dữ liệu bất biến nào khác.
  • Chỉ có thể tạo xếp hạng nếu ID người dùng khớp với người dùng đã đăng nhập, điều này ngăn chặn việc giả mạo.

Ngoài ra, ngoài việc sử dụng bảng điều khiển Firebase, bạn có thể sử dụng Firebase CLI để triển khai các quy tắc cho dự án Firebase của mình. Tệp firestore.rules trong thư mục làm việc của bạn đã chứa các quy tắc ở trên. Để triển khai các quy tắc này từ hệ thống tệp cục bộ của bạn (thay vì sử dụng bảng điều khiển Firebase), bạn hãy chạy lệnh sau:

firebase deploy --only firestore:rules

13. Kết luận

Trong lớp học lập trình này, bạn đã tìm hiểu cách thực hiện thao tác đọc và ghi cơ bản và nâng cao bằng Cloud Firestore, cũng như cách bảo mật quyền truy cập dữ liệu bằng các quy tắc bảo mật. Bạn có thể tìm thấy giải pháp đầy đủ trong kho lưu trữ quickstarts-js .

Để tìm hiểu thêm về Cloud Firestore, hãy truy cập các tài nguyên sau:

14. [Tùy chọn] Thực thi bằng Kiểm tra ứng dụng

Kiểm tra ứng dụng Firebase cung cấp khả năng bảo vệ bằng cách giúp xác thực và ngăn chặn lưu lượng truy cập không mong muốn vào ứng dụng của bạn. Trong bước này, bạn sẽ đảm bảo quyền truy cập vào các dịch vụ của mình bằng cách thêm Kiểm tra ứng dụng bằng reCAPTCHA Enterprise .

Trước tiên, bạn cần bật Kiểm tra ứng dụng và reCaptcha.

Kích hoạt reCaptcha Enterprise

  1. Trong bảng điều khiển Đám mây, tìm và chọn reCaptcha Enterprise trong phần Bảo mật.
  2. Kích hoạt dịch vụ như được nhắc và nhấp vào Create Key .
  3. Nhập tên hiển thị theo lời nhắc và chọn Trang web làm loại nền tảng của bạn.
  4. Thêm các URL đã triển khai của bạn vào danh sách Miền và đảm bảo rằng tùy chọn "Sử dụng hộp kiểm thử thách" không được chọn .
  5. Nhấp vào Tạo khóa và lưu trữ khóa đã tạo ở đâu đó để giữ an toàn. Bạn sẽ cần nó sau này trong bước này.

Bật kiểm tra ứng dụng

  1. Trong bảng điều khiển Firebase, tìm phần Xây dựng ở bảng điều khiển bên trái.
  2. Nhấp vào Kiểm tra ứng dụng , sau đó nhấp vào nút Bắt đầu (hoặc chuyển hướng trực tiếp đến bảng điều khiển ).
  3. Nhấp vào Đăng ký và nhập khóa reCaptcha Enterprise của bạn khi được nhắc, sau đó nhấp vào Lưu .
  4. Trong Chế độ xem API, chọn Lưu trữ và nhấp vào Thực thi . Làm tương tự với Cloud Firestore .

Kiểm tra ứng dụng bây giờ sẽ được thực thi! Làm mới ứng dụng của bạn và thử tạo/xem nhà hàng. Bạn sẽ nhận được thông báo lỗi:

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

Điều này có nghĩa là Kiểm tra ứng dụng đang chặn các yêu cầu không được xác thực theo mặc định. Bây giờ hãy thêm xác thực vào ứng dụng của bạn.

Điều hướng đến tệp FriendlyEats.View.js và cập nhật chức năng initAppCheck cũng như thêm khóa reCaptcha của bạn để khởi chạy Kiểm tra ứng dụng.

FriendlyEats.prototype.initAppCheck = function() {
    var appCheck = firebase.appCheck();
    appCheck.activate(
    new firebase.appCheck.ReCaptchaEnterpriseProvider(
      /* reCAPTCHA Enterprise site key */
    ),
    true // Set to true to allow auto-refresh.
  );
};

Phiên bản appCheck được khởi tạo bằng ReCaptchaEnterpriseProvider bằng khóa của bạn và isTokenAutoRefreshEnabled cho phép mã thông báo tự động làm mới trong ứng dụng của bạn.

Để bật thử nghiệm cục bộ, hãy tìm phần khởi tạo ứng dụng trong tệp FriendlyEats.js và thêm dòng sau vào hàm FriendlyEats.prototype.initAppCheck :

if(isLocalhost) {
  self.FIREBASE_APPCHECK_DEBUG_TOKEN = true;
}

Điều này sẽ ghi lại mã thông báo gỡ lỗi trong bảng điều khiển của ứng dụng web cục bộ của bạn tương tự như:

App Check debug token: 8DBDF614-649D-4D22-B0A3-6D489412838B. You will need to add it to your app's App Check settings in the Firebase console for it to work.

Bây giờ, hãy chuyển đến Chế độ xem ứng dụng của Kiểm tra ứng dụng trong bảng điều khiển Firebase.

Nhấp vào menu mục bổ sung và chọn Quản lý mã thông báo gỡ lỗi .

Sau đó, nhấp vào Thêm mã thông báo gỡ lỗi và dán mã thông báo gỡ lỗi từ bảng điều khiển của bạn như được nhắc.

Chúc mừng! Kiểm tra ứng dụng bây giờ sẽ hoạt động trong ứng dụng của bạn.