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

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

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

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

ทำความเข้าใจกฎความปลอดภัยของ Cloud Firestore

ใช้การตรวจสอบสิทธิ์ของ Firebase และ กฎความปลอดภัยของ Cloud Firestore สำหรับ Serverless การตรวจสอบสิทธิ์ การให้สิทธิ์ และการตรวจสอบข้อมูลเมื่อคุณใช้อุปกรณ์เคลื่อนที่และ ไลบรารีเว็บไคลเอ็นต์

กฎความปลอดภัยของ Cloud Firestore มี 2 ข้อดังนี้

  1. คำสั่ง match ที่ระบุเอกสารในฐานข้อมูลของคุณ
  2. นิพจน์ allow ที่ควบคุมการเข้าถึงเอกสารเหล่านั้น

การตรวจสอบสิทธิ์ Firebase จะยืนยันผู้ใช้ การรับรองเข้าสู่ระบบ และเป็นพื้นฐานสำหรับ ระบบการเข้าถึงตามบทบาทและผู้ใช้

คำขอฐานข้อมูลทุกรายการจากไลบรารีของไคลเอ็นต์เว็บ/อุปกรณ์เคลื่อนที่ใน Cloud Firestore จะได้รับการประเมินตามกฎความปลอดภัยของคุณก่อนที่จะอ่านหรือเขียนข้อมูล ถ้ากฎปฏิเสธการเข้าถึงเส้นทางเอกสารที่ระบุ พารามิเตอร์ คำขอล้มเหลว

ดูข้อมูลเพิ่มเติมเกี่ยวกับกฎความปลอดภัยของ Cloud Firestore ในหัวข้อเริ่มต้นใช้งานกฎความปลอดภัยของ Cloud Firestore

ติดตั้งโปรแกรมจำลอง

หากต้องการติดตั้งโปรแกรมจำลอง 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 และใช้กฎเหล่านั้นกับ โปรเจ็กต์ หากไม่ได้ระบุเส้นทางไฟล์ในเครื่องหรือใช้เมธอด โปรแกรมจำลองจะพิจารณาเมธอด 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 ที่แสดงการประเมินกฎความปลอดภัย

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

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

หากต้องการดูรายงาน ให้ค้นหาปลายทางที่เปิดเผยในโปรแกรมจำลอง กำลังทำงาน สำหรับเวอร์ชันที่เหมาะสำหรับเบราว์เซอร์ ให้ใช้ 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 ปกติ แต่ใน 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 ไม่ได้รับอนุญาต หากกฎของคุณตั้งค่าการทดสอบ ซับซ้อน โปรดลองใช้ RulesTestEnvironment.withSecurityRulesDisabled ในการตั้งค่า ดังนั้นการอ่านและเขียนจะไม่ทริกเกอร์ข้อผิดพลาด PERMISSION_DENIED รายการ

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