ทดสอบกฎความปลอดภัยของ Cloud Firestore

ขณะที่สร้างแอป คุณอาจต้องล็อกการเข้าถึง ฐานข้อมูล Cloud Firestore อย่างไรก็ตาม ก่อนเปิดตัว คุณจะต้องปรับแต่งให้ละเอียดยิ่งขึ้น Cloud Firestore Security Rules นอกจากการสร้างต้นแบบด้วยโปรแกรมจำลอง Cloud Firestore แล้ว และทดสอบฟีเจอร์และลักษณะการทำงานทั่วไปของแอป คุณสามารถเขียนการทดสอบ 1 หน่วยที่จะตรวจสอบลักษณะการทำงานของ Cloud Firestore Security Rules ได้

คู่มือเริ่มใช้งานฉบับย่อ

สำหรับกรอบการทดสอบพื้นฐาน 2-3 กรณีที่มีกฎง่ายๆ ลองใช้ตัวอย่างการเริ่มต้นอย่างรวดเร็ว

ทำความเข้าใจ Cloud Firestore Security Rules

ใช้ Firebase Authentication และ Cloud Firestore Security Rules สำหรับการตรวจสอบสิทธิ์ การให้สิทธิ์ และการตรวจสอบข้อมูลแบบเซิร์ฟเวอร์เสมือนเมื่อใช้ไลบรารีไคลเอ็นต์เว็บและอุปกรณ์เคลื่อนที่

Cloud Firestore Security Rules ประกอบด้วย 2 ส่วน ดังนี้

  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 ของคุณและใช้กฎเหล่านั้นกับ โปรเจ็กต์ หากไม่ได้ระบุเส้นทางไฟล์ในเครื่องหรือใช้เมธอด โปรแกรมจำลองจะพิจารณาเมธอด loadFirestoreRules ตามที่อธิบายไว้ด้านล่าง ว่ามีกฎแบบเปิด
  • ขณะที่ Firebase SDK ส่วนใหญ่ ทำงานกับโปรแกรมจำลองโดยตรง มีเพียงไลบรารี @firebase/rules-unit-testing เท่านั้นที่รองรับ จำลอง auth ในกฎความปลอดภัย ทำให้การทดสอบ 1 หน่วยง่ายขึ้นมาก นอกจากนี้ ไลบรารีสนับสนุนคุณลักษณะเฉพาะโปรแกรมจำลองบางอย่าง เช่น การล้างข้อมูลทั้งหมด ตามที่ระบุไว้ด้านล่าง
  • โปรแกรมจำลองจะยอมรับโทเค็นการตรวจสอบสิทธิ์ Firebase เวอร์ชันที่ใช้งานจริงที่ให้ไว้ด้วย ผ่าน SDK ของไคลเอ็นต์ และประเมินกฎตามนั้น ซึ่งทำให้สามารถเชื่อมต่อ แอปพลิเคชันของคุณไปยังโปรแกรมจำลองโดยตรง ทั้งในแบบผสานรวมและการทดสอบด้วยตนเอง

เรียกใช้การทดสอบหน่วยในเครื่อง

เรียกใช้การทดสอบหน่วยในเครื่องด้วย JavaScript SDK v9

Firebase เผยแพร่ไลบรารีการทดสอบหน่วยของกฎการรักษาความปลอดภัยทั้งเวอร์ชัน JavaScript SDK 9 และ SDK เวอร์ชัน 8 API ของไลบรารี แตกต่างกัน เราขอแนะนำให้ใช้ไลบรารีการทดสอบ v9 ซึ่งมีประสิทธิภาพมากกว่าและ ใช้การตั้งค่าน้อยลงในการเชื่อมต่อกับโปรแกรมจำลองและหลีกเลี่ยงการเกิดอุบัติเหตุ การใช้ทรัพยากรการผลิต เรายังคงให้บริการคลังการทดสอบ v8 ต่อไปเพื่อให้ใช้งานย้อนหลังได้

ใช้โมดูล @firebase/rules-unit-testing เพื่อโต้ตอบกับโปรแกรมจำลอง ที่ทำงานภายในเครื่อง หากได้รับข้อผิดพลาดเกี่ยวกับเวลาหมดหรือ ECONNREFUSED ให้ตรวจสอบอีกครั้งว่าโปรแกรมจำลองทำงานอยู่

เราขอแนะนำให้ใช้ Node.js เวอร์ชันล่าสุดเพื่อให้ใช้ รูปแบบ async/await ลักษณะการทำงานเกือบทั้งหมดที่คุณอาจต้องการทดสอบ รวมถึงฟังก์ชันแบบไม่พร้อมกัน และโมดูลการทดสอบได้รับการออกแบบมาให้ทำงานร่วมกับ โค้ดที่อิงตามคำมั่นสัญญา

ไลบรารีการทดสอบหน่วยกฎ v9 จะรู้จักโปรแกรมจำลองเสมอและจะไม่เลย ทรัพยากรการผลิตของคุณ

คุณนำเข้าไลบรารีโดยใช้คำสั่งการนำเข้าแบบโมดูล 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.

เมื่อนำเข้าแล้ว การใช้การทดสอบ 1 หน่วยเกี่ยวข้องกับสิ่งต่อไปนี้

  • การสร้างและกำหนดค่า RulesTestEnvironment ที่มีการเรียก initializeTestEnvironment
  • การตั้งค่าข้อมูลทดสอบโดยไม่ต้องเรียกใช้กฎ ซึ่งจะช่วยให้คุณข้ามได้ชั่วคราว RulesTestEnvironment.withSecurityRulesDisabled
  • การตั้งค่าชุดทดสอบและตามการทดสอบก่อน/หลัง ฮุกที่มีการเรียก ล้างข้อมูลและสภาพแวดล้อมการทดสอบ เช่น RulesTestEnvironment.cleanup() หรือ RulesTestEnvironment.clearFirestore()
  • การนำกรอบการทดสอบที่เลียนแบบสถานะการตรวจสอบสิทธิ์ไปใช้ RulesTestEnvironment.authenticatedContext และ RulesTestEnvironment.unauthenticatedContext

วิธีการทั่วไปและฟังก์ชันยูทิลิตี

โปรดดูวิธีทดสอบเฉพาะโปรแกรมจำลองใน SDK เวอร์ชัน 9

initializeTestEnvironment() => RulesTestEnvironment

ฟังก์ชันนี้จะเริ่มต้นสภาพแวดล้อมการทดสอบสำหรับการทดสอบหน่วยของกฎ เรียกใช้ฟังก์ชันนี้ก่อนเพื่อตั้งค่าการทดสอบ การดำเนินการที่ประสบความสำเร็จจำเป็นต้องมีโปรแกรมจำลอง วิ่งอยู่

ฟังก์ชันนี้จะยอมรับออบเจ็กต์ที่ไม่บังคับซึ่งกำหนด TestEnvironmentConfig ซึ่งอาจประกอบด้วยรหัสโปรเจ็กต์และการตั้งค่าการจําลอง

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()

เรียกใช้ฟังก์ชันการตั้งค่าการทดสอบที่มีบริบทที่ทํางานเหมือนกับว่ากฎการรักษาความปลอดภัยถูกปิดใช้

วิธีนี้ใช้ฟังก์ชัน Callback ซึ่งจะใช้การข้ามกฎ Security บริบทที่เกี่ยวข้องและแสดงคำสัญญา บริบทจะถูกทำลายเมื่อสัญญา แก้ไข / ปฏิเสธ

RulesTestEnvironment.cleanup()

เมธอดนี้จะทำลาย RulesTestContexts ทั้งหมดที่สร้างขึ้นในสภาพแวดล้อมการทดสอบและ ทำความสะอาดทรัพยากรที่สำคัญ ทำให้สามารถออกได้อย่างสมบูรณ์

วิธีนี้จะไม่เปลี่ยนสถานะของโปรแกรมจำลองไม่ว่าในทางใดก็ตาม เพื่อรีเซ็ตข้อมูล ระหว่างการทดสอบ ให้ใช้วิธีการล้างข้อมูลเฉพาะแอปพลิเคชันโปรแกรมจำลอง

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

นี่คือฟังก์ชันยูทิลิตีของเคสทดสอบ

ฟังก์ชันนี้จะยืนยันว่าการดำเนินการ Promise Wrapper ที่ระบุสิ้นสุดลง จะได้รับการแก้ไขโดยไม่ละเมิดกฎการรักษาความปลอดภัย

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

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

นี่คือฟังก์ชันยูทิลิตีของกรอบการทดสอบ

ฟังก์ชันนี้จะยืนยันว่าการดำเนินการ Promise Wrapper ที่ระบุสิ้นสุดลง จะถูกปฏิเสธเนื่องจากละเมิดกฎความปลอดภัย

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

วิธีการเฉพาะโปรแกรมจำลอง

ดูเมธอดการทดสอบทั่วไปและฟังก์ชันยูทิลิตีใน SDK เวอร์ชัน 9 ด้วย

RulesTestEnvironment.clearFirestore() => Promise<void>

วิธีนี้จะล้างข้อมูลในฐานข้อมูล Firestore ที่เป็นของ กำหนดค่า projectId สำหรับโปรแกรมจำลอง Firestore แล้ว

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

เมธอดนี้จะได้รับอินสแตนซ์ Firestore สำหรับบริบทการทดสอบนี้ ผลลัพธ์ อินสแตนซ์ SDK ของไคลเอ็นต์ Firebase JS ใช้ได้กับ API ของไคลเอ็นต์ SDK (v9 modular v9 modular) หรือความเข้ากันได้กับ v9)

แสดงภาพการประเมินกฎ

โปรแกรมจำลอง Cloud Firestore ช่วยให้คุณเห็นภาพคำขอของลูกค้าใน UI ของชุดโปรแกรมจำลอง รวมถึงการติดตามการประเมินกฎการรักษาความปลอดภัยของ Firebase

เปิด Firestore > แท็บคำขอเพื่อดูการประเมินโดยละเอียด ตามลำดับสำหรับแต่ละคำขอ

Firestore Emulator Requests Monitor ที่แสดงการประเมินกฎความปลอดภัย

สร้างรายงานการทดสอบ

หลังจากใช้งานชุดการทดสอบแล้ว คุณจะเข้าถึงการทดสอบได้ รายงานที่ครอบคลุมซึ่งแสดงวิธีประเมินกฎความปลอดภัยแต่ละกฎ

หากต้องการดูรายงาน ให้ค้นหาปลายทางที่เปิดเผยในโปรแกรมจำลอง กำลังทำงาน สำหรับเวอร์ชันที่เหมาะสำหรับเบราว์เซอร์ ให้ใช้ URL ต่อไปนี้:

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

ซึ่งจะแบ่งกฎออกเป็นนิพจน์และนิพจน์ย่อยที่ วางเมาส์เหนือข้อมูลเพิ่มเติม รวมถึงจำนวนการประเมินและค่า ส่งคืนแล้ว สำหรับเวอร์ชันข้อมูลดิบ JSON ของข้อมูลนี้ ให้ใส่ URL ต่อไปนี้ ในข้อความค้นหาของคุณ:

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()
  • การยืนยันการดำเนินการ ซึ่งรวมถึง assertSucceeds และ assertFails

การทดสอบจะผ่านในครั้งแรกที่คุณโหลดโปรแกรมจำลองเท่านั้น

โปรแกรมจำลองเป็นแบบเก็บสถานะ โดยระบบจะจัดเก็บข้อมูลทั้งหมดที่เขียนลงในหน่วยความจำ ดังนั้นข้อมูลทั้งหมดจะหายไปเมื่อปิดโปรแกรมจำลอง หากคุณใช้งาน โดยเทียบกับรหัสโครงการเดียวกัน การทดสอบแต่ละครั้งสามารถให้ข้อมูลที่อาจ ส่งผลต่อการทดสอบครั้งต่อๆ ไป คุณสามารถใช้วิธีการใดก็ได้ต่อไปนี้เพื่อ ให้หลีกเลี่ยงลักษณะการทำงานนี้

  • ใช้รหัสโปรเจ็กต์ที่ไม่ซ้ำกันสำหรับการทดสอบแต่ละครั้ง โปรดทราบว่าหากคุณเลือกดำเนินการดังกล่าว จะต้องโทรหา initializeTestEnvironment เป็นส่วนหนึ่งของการทดสอบแต่ละครั้ง กฎ จะโหลดโดยอัตโนมัติสำหรับรหัสโปรเจ็กต์เริ่มต้นเท่านั้น
  • ปรับโครงสร้างการทดสอบใหม่เพื่อไม่ให้โต้ตอบกับข้อมูลที่เขียนไว้ก่อนหน้านี้ (เช่น ใช้คอลเล็กชันอื่นสําหรับการทดสอบแต่ละรายการ)
  • ลบข้อมูลทั้งหมดที่เขียนระหว่างการทดสอบ

การตั้งค่าการทดสอบซับซ้อนมาก

เมื่อตั้งค่าการทดสอบ คุณอาจต้องการแก้ไขข้อมูลในลักษณะ Cloud Firestore Security Rules ไม่อนุญาต หากกฎของคุณตั้งค่าการทดสอบ ซับซ้อน โปรดลองใช้ RulesTestEnvironment.withSecurityRulesDisabled ในการตั้งค่า ดังนั้นการอ่านและเขียนจะไม่ทริกเกอร์ข้อผิดพลาด PERMISSION_DENIED รายการ

หลังจากนั้น การทดสอบของคุณสามารถดำเนินการต่างๆ ได้ตามสถานะที่ได้รับหรือไม่ผ่านการตรวจสอบสิทธิ์ ผู้ใช้ที่ใช้ RulesTestEnvironment.authenticatedContext และ unauthenticatedContext ตามลำดับ วิธีนี้ช่วยให้คุณตรวจสอบได้ว่า Cloud Firestore Security Rules อนุญาต/ปฏิเสธ เคสต่างๆ อย่างถูกต้อง