Kiểm tra Quy tắc bảo mật Cloud Firestore của bạn

Khi đang xây dựng ứng dụng của mình, bạn có thể muốn khóa quyền truy cập vào cơ sở dữ liệu Cloud Firestore của mình. Tuy nhiên, trước khi khởi chạy, bạn sẽ cần Quy tắc bảo mật Cloud Firestore nhiều sắc thái hơn. Với trình giả lập Cloud Firestore, ngoài việc tạo mẫu và thử nghiệm các tính năng và hành vi chung của ứng dụng, bạn có thể viết các bài kiểm tra đơn vị để kiểm tra hoạt động của Quy tắc bảo mật Cloud Firestore của bạn.

Bắt đầu nhanh

Đối với một số trường hợp thử nghiệm cơ bản với các quy tắc đơn giản, hãy thử mẫu bắt đầu nhanh .

Hiểu các quy tắc bảo mật Cloud Firestore

Triển khai Xác thực FirebaseQuy tắc bảo mật Cloud Firestore để xác thực không máy chủ, ủy quyền và xác thực dữ liệu khi bạn sử dụng thư viện ứng dụng khách web và di động.

Quy tắc bảo mật Cloud Firestore bao gồm hai phần:

  1. Một câu lệnh match xác định các tài liệu trong cơ sở dữ liệu của bạn.
  2. Biểu thức allow kiểm soát quyền truy cập vào các tài liệu đó.

Xác thực Firebase xác minh thông tin đăng nhập của người dùng và cung cấp nền tảng cho các hệ thống truy cập dựa trên vai trò và người dùng.

Mọi yêu cầu cơ sở dữ liệu từ thư viện máy khách web / di động Cloud Firestore đều được đánh giá dựa trên các quy tắc bảo mật của bạn trước khi đọc hoặc ghi bất kỳ dữ liệu nào. Nếu các quy tắc từ chối quyền truy cập vào bất kỳ đường dẫn tài liệu nào được chỉ định, thì toàn bộ yêu cầu sẽ không thành công.

Tìm hiểu thêm về Quy tắc bảo mật Cloud Firestore trong Bắt đầu với Quy tắc bảo mật Cloud Firestore .

Cài đặt trình giả lập

Để cài đặt trình giả lập Cloud Firestore, hãy sử dụng Firebase CLI và chạy lệnh bên dưới:

firebase setup:emulators:firestore

Chạy trình giả lập

Bắt đầu bằng cách khởi tạo một dự án Firebase trong thư mục làm việc của bạn. Đây là bước đầu tiên phổ biến khi sử dụng Firebase CLI .

firebase init

Khởi động trình giả lập bằng lệnh sau. Trình giả lập sẽ chạy cho đến khi bạn kết thúc quá trình:

firebase emulators:start --only firestore

Trong nhiều trường hợp, bạn muốn khởi động trình giả lập, hãy chạy bộ thử nghiệm, sau đó tắt trình giả lập sau khi chạy thử nghiệm. Bạn có thể thực hiện việc này một cách dễ dàng bằng cách sử dụng emulators:exec :

firebase emulators:exec --only firestore "./my-test-script.sh"

Khi khởi động, trình giả lập sẽ cố gắng chạy trên một cổng mặc định (8080). Bạn có thể thay đổi cổng trình giả lập bằng cách sửa đổi phần "emulators" trong tệp firebase.json của mình:

{
  // ...
  "emulators": {
    "firestore": {
      "port": "YOUR_PORT"
    }
  }
}

Trước khi bạn chạy trình giả lập

Trước khi bạn bắt đầu sử dụng trình giả lập, hãy ghi nhớ những điều sau:

  • Trình mô phỏng ban đầu sẽ tải các quy tắc được chỉ định trong trường firestore.rules của tệp firebase.json của bạn. Nó mong đợi tên của một tệp cục bộ chứa Quy tắc bảo mật Cloud Firestore của bạn và áp dụng các quy tắc đó cho tất cả các dự án. Nếu bạn không cung cấp đường dẫn tệp cục bộ hoặc sử dụng phương thức loadFirestoreRules như được mô tả bên dưới, trình giả lập sẽ coi tất cả các dự án là có quy tắc mở.
  • Mặc dù hầu hết các SDK Firebase hoạt động trực tiếp với trình giả lập, nhưng chỉ có thư viện @firebase/rules-unit-testing mới hỗ trợ mocking auth trong Quy tắc bảo mật, giúp kiểm tra đơn vị dễ dàng hơn nhiều. Ngoài ra, thư viện hỗ trợ một số tính năng dành riêng cho trình giả lập như xóa tất cả dữ liệu, như được liệt kê bên dưới.
  • Trình giả lập cũng sẽ chấp nhận mã thông báo Firebase Auth sản xuất được cung cấp thông qua SDK khách hàng và đánh giá các quy tắc cho phù hợp, cho phép kết nối ứng dụng của bạn trực tiếp với trình giả lập trong quá trình tích hợp và kiểm tra thủ công.

Chạy thử nghiệm đơn vị cục bộ

Chạy thử nghiệm đơn vị cục bộ với SDK JavaScript v9

Firebase phân phối thư viện thử nghiệm đơn vị Quy tắc bảo mật với cả SDK JavaScript phiên bản 9 và SDK phiên bản 8 của nó. Các API thư viện khác nhau đáng kể. Chúng tôi đề xuất thư viện thử nghiệm v9, được sắp xếp hợp lý hơn và yêu cầu ít thiết lập hơn để kết nối với trình giả lập và do đó tránh sử dụng ngẫu nhiên tài nguyên sản xuất một cách an toàn. Để có khả năng tương thích ngược, chúng tôi tiếp tục cung cấp thư viện thử nghiệm v8 .

Sử dụng mô-đun @firebase/rules-unit-testing để tương tác với trình mô phỏng chạy cục bộ. Nếu bạn gặp lỗi hết thời gian chờ hoặc lỗi ECONNREFUSED , hãy kiểm tra kỹ xem trình giả lập có đang thực sự chạy hay không.

Chúng tôi thực sự khuyên bạn nên sử dụng phiên bản gần đây của Node.js để bạn có thể sử dụng ký hiệu async/await . Hầu như tất cả các hành vi bạn có thể muốn kiểm tra đều liên quan đến các chức năng không đồng bộ và mô-đun kiểm tra được thiết kế để hoạt động với mã dựa trên Promise.

Thư viện Kiểm tra Đơn vị Quy tắc v9 luôn biết các trình giả lập và không bao giờ động đến tài nguyên sản xuất của bạn.

Bạn nhập thư viện bằng cách sử dụng câu lệnh nhập mô-đun v9. Ví dụ:

import {
  assertFails,
  assertSucceeds,
  initializeTestEnvironment,
  RulesTestEnvironment,
} from "@firebase/rules-unit-testing"

// Use `const { … } = require("@firebase/rules-unit-testing")` if imports are not supported
// Or we suggest `const testing = require("@firebase/rules-unit-testing")` if necessary.

Sau khi được nhập, việc triển khai các bài kiểm tra đơn vị bao gồm:

  • Tạo và cấu hình một RulesTestEnvironment bằng lệnh gọi initializeTestEnvironment tạoTestEn Môi trường.
  • Thiết lập dữ liệu thử nghiệm mà không kích hoạt Quy tắc, sử dụng một phương pháp tiện lợi cho phép bạn tạm thời bỏ qua chúng, RulesTestEnvironment.withSecurityRulesDisabled .
  • Thiết lập bộ kiểm tra và mỗi bài kiểm tra trước / sau kết nối với các lệnh gọi để dọn dẹp dữ liệu kiểm tra và môi trường, như RulesTestEnvironment.cleanup() hoặc RulesTestEnvironment.clearFirestore() .
  • Triển khai các trường hợp thử nghiệm bắt chước các trạng thái xác thực bằng RulesTestEnvironment.authenticatedContextRulesTestEnvironment.unauthenticatedContext .

Các phương pháp phổ biến và các chức năng tiện ích

Ngoài ra, hãy xem các phương pháp kiểm tra dành riêng cho trình mô phỏng trong SDK v9 .

initializeTestEnvironment() => RulesTestEnvironment

Chức năng này khởi tạo một môi trường thử nghiệm để thử nghiệm đơn vị quy tắc. Gọi chức năng này trước để thiết lập thử nghiệm. Việc thực thi thành công yêu cầu trình giả lập đang chạy.

Hàm chấp nhận một đối tượng tùy chọn xác định TestEnvironmentConfig , có thể bao gồm ID dự án và cài đặt cấu hình trình mô phỏng.

let testEnv = await initializeTestEnvironment({
  projectId: "demo-project-1234",
  firestore: {
    rules: fs.readFileSync("firestore.rules", "utf8"),
  },
});

RulesTestEnvironment.authenticatedContext({ user_id: string, tokenOptions?: TokenOptions }) => RulesTestContext

Phương thức này tạo ra một RulesTestContext , hoạt động giống như một người dùng Xác thực đã được xác thực. Các yêu cầu được tạo thông qua ngữ cảnh được trả về sẽ có mã thông báo Xác thực giả được đính kèm. Theo tùy chọn, chuyển một đối tượng xác định xác nhận quyền sở hữu hoặc ghi đè tùy chỉnh cho tải trọng mã thông báo Xác thực.

Sử dụng đối tượng ngữ cảnh thử nghiệm được trả về trong các thử nghiệm của bạn để truy cập vào bất kỳ phiên bản trình giả lập nào được định cấu hình, bao gồm cả những phiên bản được định cấu hình với initializeTestEnvironment .

// Assuming a Firestore app and the Firestore emulator for this example
import { setDoc } from "firebase/firestore";

const alice = testEnv.authenticatedContext("alice", { … });
// Use the Firestore instance associated with this context
await assertSucceeds(setDoc(alice.firestore(), '/users/alice'), { ... });

RulesTestEnvironment.unauthenticatedContext() => RulesTestContext

Phương thức này tạo ra một RulesTestContext , hoạt động giống như một ứng dụng khách không được đăng nhập qua Xác thực. Các yêu cầu được tạo thông qua ngữ cảnh được trả về sẽ không có mã thông báo Firebase Auth được đính kèm.

Sử dụng đối tượng ngữ cảnh thử nghiệm được trả về trong các thử nghiệm của bạn để truy cập vào bất kỳ phiên bản trình giả lập nào được định cấu hình, bao gồm cả những phiên bản được định cấu hình với initializeTestEnvironment .

// Assuming a Cloud Storage app and the Storage emulator for this example
import { getStorage, ref, deleteObject } from "firebase/storage";

const alice = testEnv.unauthenticatedContext();

// Use the Cloud Storage instance associated with this context
const desertRef = ref(alice.storage(), 'images/desert.jpg');
await assertSucceeds(deleteObject(desertRef));

RulesTestEnvironment.withSecurityRulesDisabled()

Chạy chức năng thiết lập thử nghiệm với ngữ cảnh hoạt động như thể Quy tắc bảo mật đã bị vô hiệu hóa.

Phương thức này sử dụng một hàm gọi lại, hàm này nhận bối cảnh Bảo mật-Quy tắc-bỏ qua và trả về một lời hứa. Bối cảnh sẽ bị hủy sau khi lời hứa được giải quyết / từ chối.

RulesTestEnvironment.cleanup()

Phương pháp này phá hủy tất cả các RulesTestContexts được tạo trong môi trường thử nghiệm và dọn dẹp các tài nguyên bên dưới, cho phép thoát sạch.

Phương pháp này không thay đổi trạng thái của trình giả lập theo bất kỳ cách nào. Để đặt lại dữ liệu giữa các lần kiểm tra, hãy sử dụng phương pháp dữ liệu rõ ràng dành riêng cho trình mô phỏng ứng dụng.

assertSucceeds(pr: Promise<any>)) => Promise<any>

Đây là một chức năng tiện ích trường hợp thử nghiệm.

Chức năng khẳng định rằng Promise được cung cấp gói một hoạt động giả lập sẽ được giải quyết mà không vi phạm Quy tắc bảo mật.

await assertSucceeds(setDoc(alice.firestore(), '/users/alice'), { ... });

assertFails(pr: Promise<any>)) => Promise<any>

Đây là một chức năng tiện ích trường hợp thử nghiệm.

Hàm xác nhận rằng Promise được cung cấp gói một hoạt động giả lập sẽ bị từ chối do vi phạm Quy tắc bảo mật.

await assertFails(setDoc(alice.firestore(), '/users/bob'), { ... });

Các phương pháp dành riêng cho trình giả lập

Ngoài ra, hãy xem các phương pháp kiểm tra phổ biến và các chức năng tiện ích trong SDK v9 .

RulesTestEnvironment.clearFirestore() => Promise<void>

Phương pháp này xóa dữ liệu trong cơ sở dữ liệu Firestore thuộc về projectId định cấu hình cho trình giả lập Firestore.

RulesTestContext.firestore(settings?: Firestore.FirestoreSettings) => Firestore;

Phương thức này nhận được một phiên bản Firestore cho ngữ cảnh thử nghiệm này. Phiên bản SDK ứng dụng khách Firebase JS trả về có thể được sử dụng với các API SDK ứng dụng khách (v9 mô-đun hoặc v9 compat).

Hình dung các đánh giá quy tắc

Trình giả lập Cloud Firestore cho phép bạn trực quan hóa các yêu cầu của khách hàng trong Giao diện người dùng của Emulator Suite, bao gồm cả việc theo dõi đánh giá đối với Quy tắc bảo mật của Firebase.

Mở tab Firestore> Yêu cầu để xem trình tự đánh giá chi tiết cho từng yêu cầu.

Màn hình yêu cầu trình giả lập Firestore hiển thị đánh giá Quy tắc bảo mật

Tạo báo cáo thử nghiệm

Sau khi chạy một bộ kiểm tra, bạn có thể truy cập các báo cáo phạm vi kiểm tra cho biết từng quy tắc bảo mật của bạn đã được đánh giá như thế nào.

Để nhận báo cáo, hãy truy vấn một điểm cuối được tiếp xúc trên trình giả lập khi nó đang chạy. Đối với phiên bản thân thiện với trình duyệt, hãy sử dụng URL sau:

http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage.html

Điều này phá vỡ các quy tắc của bạn thành các biểu thức và biểu thức con mà bạn có thể di chuột qua để biết thêm thông tin, bao gồm số lượng đánh giá và giá trị được trả về. Đối với phiên bản JSON thô của dữ liệu này, hãy bao gồm URL sau trong truy vấn của bạn:

http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage

Sự khác biệt giữa trình giả lập và sản xuất

  1. Bạn không cần phải tạo dự án Cloud Firestore một cách rõ ràng. Trình giả lập tự động tạo bất kỳ phiên bản nào được truy cập.
  2. Trình giả lập Cloud Firestore không hoạt động với quy trình Xác thực Firebase thông thường. Thay vào đó, trong SDK kiểm tra Firebase, chúng tôi đã cung cấp phương thức initializeTestApp() trong thư viện rules-unit-testing , sử dụng trường auth . Tay cầm Firebase được tạo bằng phương pháp này sẽ hoạt động như thể nó đã được xác thực thành công dưới dạng bất kỳ thực thể nào bạn cung cấp. Nếu bạn chuyển bằng null , nó sẽ hoạt động như một người dùng chưa được xác thực (ví dụ: các quy tắc auth != null sẽ không thành công).

Khắc phục sự cố đã biết

Khi sử dụng trình giả lập Cloud Firestore, bạn có thể gặp phải các sự cố đã biết sau đây. Làm theo hướng dẫn bên dưới để khắc phục mọi hành vi bất thường mà bạn đang gặp phải. Các ghi chú này được viết với thư viện kiểm tra đơn vị Quy tắc bảo mật, nhưng các phương pháp chung có thể áp dụng cho bất kỳ SDK Firebase nào.

Hành vi kiểm tra không nhất quán

Nếu các bài kiểm tra của bạn thỉnh thoảng đạt và không đạt, ngay cả khi không có bất kỳ thay đổi nào đối với bản thân các bài kiểm tra, bạn có thể cần xác minh rằng chúng được sắp xếp đúng trình tự. Hầu hết các tương tác với trình giả lập là không đồng bộ, vì vậy hãy kiểm tra kỹ xem tất cả mã không đồng bộ có được sắp xếp đúng trình tự hay không. Bạn có thể sửa trình tự bằng cách xâu chuỗi các lời hứa hoặc sử dụng ký hiệu await một cách tự do.

Đặc biệt, hãy xem lại các hoạt động không đồng bộ sau:

  • Đặt các quy tắc bảo mật, ví dụ: initializeTestEnvironment .
  • Đọc và ghi dữ liệu, ví dụ: với db.collection("users").doc("alice").get() .
  • Xác nhận hoạt động, bao gồm assertSucceedsassertFails .

Các bài kiểm tra chỉ vượt qua lần đầu tiên bạn tải trình giả lập

Trình giả lập là trạng thái. Nó lưu trữ tất cả dữ liệu được ghi vào bộ nhớ, vì vậy mọi dữ liệu sẽ bị mất bất cứ khi nào trình giả lập tắt. Nếu bạn đang chạy nhiều thử nghiệm với cùng một id dự án, mỗi thử nghiệm có thể tạo ra dữ liệu có thể ảnh hưởng đến các thử nghiệm tiếp theo. Bạn có thể sử dụng bất kỳ phương pháp nào sau đây để bỏ qua hành vi này:

  • Sử dụng các ID dự án duy nhất cho mỗi thử nghiệm. Lưu ý rằng nếu bạn chọn làm điều này, bạn sẽ cần gọi initializeTestEnvironment như một phần của mỗi bài kiểm tra; quy tắc chỉ được tải tự động cho ID dự án mặc định.
  • Cấu trúc lại các bài kiểm tra của bạn để chúng không tương tác với dữ liệu đã viết trước đó (ví dụ: sử dụng một bộ sưu tập khác nhau cho mỗi bài kiểm tra).
  • Xóa tất cả dữ liệu được ghi trong quá trình kiểm tra.

Thiết lập kiểm tra rất phức tạp

Khi thiết lập thử nghiệm, bạn có thể muốn sửa đổi dữ liệu theo cách mà Quy tắc bảo mật Cloud Firestore của bạn không thực sự cho phép. Nếu các quy tắc của bạn đang làm cho việc thiết lập thử nghiệm trở nên phức tạp, hãy thử sử dụng RulesTestEnvironment.withSecurityRulesDisabled trong các bước thiết lập của bạn, do đó, việc đọc và ghi sẽ không gây ra lỗi PERMISSION_DENIED .

Sau đó, thử nghiệm của bạn có thể thực hiện các hoạt động với tư cách là người dùng được xác thực hoặc chưa được xác thực bằng cách sử dụng RulesTestEnvironment.authenticatedContextunauthenticatedContext tương ứng. Điều này cho phép bạn xác nhận rằng Quy tắc bảo mật Cloud Firestore của bạn cho phép / từ chối các trường hợp khác nhau một cách chính xác.