測試 Cloud Firestore 安全性規則

建構應用程式時,建議您鎖定 Cloud Firestore 資料庫。不過,在正式推出應用程式前,您可能會需要 Cloud Firestore Security Rules。使用 Cloud Firestore 模擬器時,除了設計原型以外 以及測試應用程式的一般功能與行為。 您可以編寫單元測試來檢查 Cloud Firestore Security Rules 的行為。

快速入門導覽課程

如需使用簡單規則的幾個基本測試案例,請參考快速入門導覽課程範例

瞭解 Cloud Firestore Security Rules

導入 Firebase AuthenticationCloud Firestore Security Rules 適用於無伺服器 驗證、授權和資料驗證 網路用戶端程式庫

Cloud Firestore Security Rules 包含兩個部分:

  1. match 陳述式,用於識別資料庫中的文件。
  2. 控制這些文件存取權的 allow 運算式。

Firebase Authentication 會驗證使用者的憑證,並提供以使用者和角色為基礎的存取權系統基礎。

來自 Cloud Firestore 行動/網路用戶端程式庫的每項資料庫要求 會根據您的安全性規則評估,然後再讀取或寫入任何資料。 如果規則拒絕存取任何指定的文件路徑,系統會在 要求失敗。

如要進一步瞭解 Cloud Firestore Security Rules,請參閱開始使用 Cloud Firestore Security Rules

安裝模擬器

如要安裝 Cloud Firestore 模擬器,請使用 Firebase CLI 然後執行下列指令:

firebase setup:emulators:firestore

執行模擬器

請先在工作目錄中初始化 Firebase 專案。這是 使用 Firebase CLI 時,常見的第一步。

firebase init

使用下列指令啟動模擬器。模擬器將會執行 直到終止程序:

firebase emulators:start --only firestore

在許多情況下,您會想要啟動模擬器、執行測試套件,然後在測試執行後關閉模擬器。只要使用以下工具即可輕鬆操作: emulators:exec 指令:

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

啟動模擬器時,模擬器會嘗試在預設通訊埠 (8080) 上執行。你可以 修改模擬器的 "emulators" 區段, firebase.json 檔案:

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

執行模擬器前

開始使用模擬器前,請注意下列事項:

  • 模擬器一開始會載入 firestore.rules 中指定的規則 欄位的值firebase.json。它需要一個 包含 Cloud Firestore Security Rules 的本機檔案,並將這些規則套用到所有 Google Cloud 的 Resource Manager 工具 經特別設計,能以程式輔助方式協助您管理專案如未提供本機檔案路徑,或使用 如下所述 loadFirestoreRules 方法,模擬器會把所有內容視為 管理專案
  • 雖然 大部分 Firebase SDK 只能直接和模擬器搭配使用,只有 @firebase/rules-unit-testing 程式庫支援 模擬安全性規則中的 auth 可簡化單元測試。此外, 程式庫支援幾項模擬器專屬功能,例如清除所有資料 說明。
  • 模擬器也會接受你提供的正式版 Firebase 驗證權杖 並透過用戶端 SDK 據此評估規則 即可將您的應用程式直接傳送至模擬器,並進行手動測試。

執行本機單元測試

使用第 9 版 JavaScript SDK 執行本機單元測試

Firebase 發布了同時包含兩個版本的安全性規則單元測試程式庫 9 JavaScript SDK 和第 8 版 SDK。程式庫 API 主要 也不一樣建議您使用更精簡的 v9 測試程式庫 連線至模擬器所需的設定較少,因此可以安全避免意外 控管正式環境資源的方式為了回溯相容性,我們會繼續提供 v8 測試程式庫

使用 @firebase/rules-unit-testing 模組與模擬器互動 執行在本機的容器如果出現逾時或 ECONNREFUSED 錯誤,請仔細檢查模擬器是否確實正在執行。

強烈建議您使用新版 Node.js,以便使用 async/await 標記法。您想要測試的所有行為 涉及非同步函式,而測試模組的設計宗旨是讓 以 Promise 為基礎的程式碼。

v9 Rules 單元測試程式庫一律會感知模擬器, 您會很熟悉生產資源

您可使用 v9 模組匯入陳述式匯入程式庫。例如:

import {
  assertFails,
  assertSucceeds,
  initializeTestEnvironment
} 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.

匯入後,實作單元測試涉及:

  • 建立及設定 RulesTestEnvironment,其中包含呼叫 initializeTestEnvironment
  • 輕鬆設定測試資料,但不觸發規則 方法可讓您暫時略過 RulesTestEnvironment.withSecurityRulesDisabled
  • 設定測試套件,並在掛鉤前後進行個別測試 清除測試資料和環境 (例如 RulesTestEnvironment.cleanup()) 或 RulesTestEnvironment.clearFirestore()
  • 使用 「RulesTestEnvironment.authenticatedContext」和 RulesTestEnvironment.unauthenticatedContext
,瞭解如何調查及移除這項存取權。

常用方法與公用程式函式

另請參閱 第 9 版 SDK 中的模擬器專屬測試方法

initializeTestEnvironment() => RulesTestEnvironment

這個函式會初始化規則單元測試的測試環境。呼叫此項目 函式,用於測試設定。成功執行需要模擬器必須 備用資源

這個函式會接受選用的物件,定義 TestEnvironmentConfig,其中可以包含專案 ID 和模擬器設定。

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

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

這個方法會建立 RulesTestContext,其運作方式類似於經過驗證的 驗證使用者。透過傳回的結構定義建立的要求,會附加模擬驗證權的符記。視需求傳送定義自訂憑證附加資訊的物件 驗證權杖酬載的覆寫值

在測試中使用傳回的測試情境物件存取任何模擬器 設定的執行個體,包括使用 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

這個方法會建立 RulesTestContext,運作方式就像用戶端 未透過「驗證」登入。透過傳回的結構定義建立的要求不會 已附加 Firebase 驗證權杖。

在測試中使用傳回的測試情境物件存取任何模擬器 設定的執行個體,包括使用 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()

在與安全性規則停用時相同的情況下,執行測試設定函式。

這個方法採用回呼函式,這會將安全性規則略過 並傳回承諾。承諾解析/拒絕後,系統就會銷毀這個內容。

RulesTestEnvironment.cleanup()

這個方法會刪除在測試環境中建立的所有 RulesTestContexts,並 這會清除基礎資源,以便順暢結束作業。

這個方法不會以任何方式變更模擬器的狀態。重設資料的方式 請使用應用程式模擬器專屬的清除資料方法,才能進行測試。

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

這是測試案例公用程式函式。

這個函式會斷言,提供的包裝模擬器作業的 Promise 會在沒有違反安全規則的情況下解析。

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

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

這是測試案例公用程式。

這個函式會斷言,提供的包裝模擬器作業的 Promise 會因違反安全性規則而遭到拒絕。

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

Android Emulator 專用方法

另請參閱「第 9 版 SDK 中的常見測試方法和公用程式函式」。

RulesTestEnvironment.clearFirestore() => Promise<void>

這個方法會清除屬於 為 Firestore 模擬器設定的 projectId

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

這個方法會取得此測試結構定義的 Firestore 執行個體。傳回的 Firebase JS Client SDK 例項可搭配用戶端 SDK API (第 9 版模組化或第 9 版相容性) 使用。

以圖表呈現規則評估結果

Cloud Firestore 模擬器可讓您以視覺化方式呈現用戶端要求, 模擬器套件 UI,包括 Firebase 安全性規則的評估追蹤。

開啟 Firestore >要求分頁,以查看詳細評估 序列。

顯示安全性規則評估作業的 Firestore 模擬器要求監控項目

產生測試報告

執行一系列測試後 涵蓋範圍報告,其中顯示各項安全性規則的評估方式。

如要取得報表,請在模擬器執行期間查詢公開的端點。如果是適用於瀏覽器的版本,請使用下列網址:

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

這會將規則分為可兌換的運算式和子運算式 滑鼠遊標懸停即可查看更多資訊,包括評估數量和值 。這項資料的原始 JSON 版本包含以下網址 :

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

模擬器和正式版的差異

  1. 您不必明確建立 Cloud Firestore 專案。模擬器 會自動建立任何可存取的執行個體。
  2. Cloud Firestore 模擬器不適用於一般 Firebase Authentication 流程。 而是在 Firebase Test SDK 中提供 initializeTestApp() 方法, rules-unit-testing 程式庫,採用 auth 欄位。已建立的 Firebase 帳號代碼 此方法就會表現出 使用您提供的任何實體如果傳入 null,系統會視為 未經驗證的使用者 (例如 auth != null 規則將失敗)。

排解已知問題

使用 Cloud Firestore 模擬器時,您可能會遇到以下已知情況 以負載平衡機制分配流量 即可降低應用程式發生效能問題的風險請按照下方指引排解您遇到的任何異常行為 體驗。這些附註是透過安全性規則單元測試所編寫 不過這些通用做法適用於任何 Firebase SDK。

測試行為不一致

如果測試偶爾會通過並失敗,即使未變更 因此您可能需要確認測試的正確順序。 大多數與模擬器的互動皆為非同步性質,因此請仔細檢查所有操作 非同步程式碼的順序正確您可以透過下列任一方法修正序列 鏈結承諾,或任意使用 await 標記法。

請特別留意下列非同步作業:

  • 設定安全性規則,例如 initializeTestEnvironment
  • 讀取及寫入資料,例如 db.collection("users").doc("alice").get()
  • 操作斷言,包括 assertSucceedsassertFails

只有在首次載入模擬器時,測試才會通過

模擬器處於有狀態狀態。它會將寫入的所有資料儲存在記憶體中 每當模擬器關閉時,任何資料都會遺失。如果您同時執行多個 以相同的專案 ID 進行測試,每項測試都能產生符合以下描述的資料: 影響後續的測試您可以使用下列任一方法略過這項行為:

  • 請為每個測試使用不重複的專案 ID。請注意,如果您選擇這麼做 需要在每項測試中呼叫 initializeTestEnvironment。規則 只會自動載入預設的專案 ID。
  • 重新建構測試,讓測試不會與先前寫入的資料互動 (例如每項測試使用不同的集合)。
  • 刪除在測試期間寫入的所有資料。

測試設定非常複雜

設定測試時,可能需要 「Cloud Firestore Security Rules」實際上並未允許。如果您的規則要設定測試 複雜,請嘗試在設定中使用 RulesTestEnvironment.withSecurityRulesDisabled 因此,讀取和寫入不會觸發 PERMISSION_DENIED 錯誤。

之後,您的測試能以驗證或未驗證的身分執行作業 使用者 (使用 RulesTestEnvironment.authenticatedContextunauthenticatedContext) 。這樣一來,您就能驗證 Cloud Firestore Security Rules 是否正確允許/拒絕不同情況。