คุณอาจต้องการล็อกการเข้าถึงฐานข้อมูล Cloud Firestore ไว้ขณะที่สร้างแอป อย่างไรก็ตาม ก่อนเปิดตัว คุณจะต้องปรับแต่งให้ละเอียดยิ่งขึ้น Cloud Firestore Security Rules เมื่อใช้โปรแกรมจำลอง Cloud Firestore นอกจากการสร้างต้นแบบและการทดสอบฟีเจอร์และลักษณะการทำงานทั่วไปของแอปแล้ว คุณยังเขียนการทดสอบหน่วยที่จะตรวจสอบลักษณะการทำงานของ Cloud Firestore Security Rules ได้ด้วย
คู่มือเริ่มใช้งานฉบับย่อ
สําหรับเฟรมเวิร์กการทดสอบพื้นฐาน 2-3 รายการที่มีกฎง่ายๆ ให้ลองใช้ตัวอย่างการเริ่มต้นใช้งานฉบับย่อ
ทำความเข้าใจ Cloud Firestore Security Rules
ใช้ Firebase Authentication และ Cloud Firestore Security Rules สำหรับการตรวจสอบสิทธิ์ การให้สิทธิ์ และการตรวจสอบข้อมูลแบบเซิร์ฟเวอร์เสมือนเมื่อใช้ไลบรารีไคลเอ็นต์เว็บและอุปกรณ์เคลื่อนที่
Cloud Firestore Security Rules ประกอบด้วย 2 ส่วน ได้แก่
- คำสั่ง
match
ที่ระบุเอกสารในฐานข้อมูล - นิพจน์
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
วิธีการตามที่อธิบายไว้ด้านล่าง เครื่องจำลองจะถือว่าโปรเจ็กต์ทั้งหมดมีกฎแบบเปิด - แม้ว่าSDK ของ Firebase ส่วนใหญ่จะทํางานกับโปรแกรมจําลองโดยตรง แต่มีเพียงไลบรารี
@firebase/rules-unit-testing
เท่านั้นที่รองรับการจําลองauth
ในกฎการรักษาความปลอดภัย ซึ่งทําให้การทดสอบหน่วยง่ายขึ้นมาก นอกจากนี้ ไลบรารียังรองรับฟีเจอร์บางอย่างเฉพาะสำหรับโปรแกรมจำลอง เช่น การล้างข้อมูลทั้งหมด ตามที่ระบุไว้ด้านล่าง - นอกจากนี้ โปรแกรมจำลองจะยอมรับโทเค็นการตรวจสอบสิทธิ์ Firebase เวอร์ชันที่ใช้งานจริงซึ่งให้ผ่าน Client SDK และประเมินกฎตามความเหมาะสม ซึ่งช่วยให้เชื่อมต่อแอปพลิเคชันกับโปรแกรมจำลองได้โดยตรงในการผสานรวมและการทดสอบด้วยตนเอง
เรียกใช้การทดสอบหน่วยในเครื่อง
เรียกใช้การทดสอบหน่วยในเครื่องด้วย JavaScript SDK เวอร์ชัน 9
Firebase เผยแพร่ไลบรารีการทดสอบยูนิตของกฎความปลอดภัยทั้งกับ JavaScript SDK เวอร์ชัน 9 และ SDK เวอร์ชัน 8 API ของไลบรารีแตกต่างกันอย่างมาก เราขอแนะนําให้ใช้คลังการทดสอบ v9 ซึ่งมีประสิทธิภาพมากขึ้นและตั้งค่าเพื่อเชื่อมต่อกับโปรแกรมจำลองได้ง่ายขึ้น จึงหลีกเลี่ยงการใช้ทรัพยากรเวอร์ชันที่ใช้งานจริงโดยไม่ตั้งใจได้อย่างปลอดภัย เรายังคงให้บริการคลังการทดสอบ v8 ต่อไปเพื่อให้ใช้งานย้อนหลังได้
- วิธีทดสอบทั่วไปและฟังก์ชันยูทิลิตีใน SDK เวอร์ชัน 9
- วิธีทดสอบเฉพาะสำหรับโปรแกรมจำลองใน SDK เวอร์ชัน 9
ใช้โมดูล @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.
เมื่อนำเข้าแล้ว การใช้การทดสอบหน่วยจะเกี่ยวข้องกับการดำเนินการต่อไปนี้
- การสร้างและกำหนดค่า
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 Auth แนบอยู่
ใช้ออบเจ็กต์บริบทการทดสอบที่แสดงผลในการทดสอบเพื่อเข้าถึงอินสแตนซ์โปรแกรมจำลองที่กําหนดค่าไว้ รวมถึงอินสแตนซ์ที่กําหนดค่าด้วย 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 ซึ่งใช้บริบทการลบล้างกฎด้านความปลอดภัยและแสดงผลพรอมต์ บริบทจะถูกทำลายเมื่อ Promise ดำเนินการเสร็จสมบูรณ์/ปฏิเสธ
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'), { ... });
วิธีการเฉพาะโปรแกรมจำลอง
ดูเมธอดการทดสอบทั่วไปและฟังก์ชันยูทิลิตีใน SDK เวอร์ชัน 9 ด้วย
RulesTestEnvironment.clearFirestore() => Promise<void>
วิธีนี้จะล้างข้อมูลในฐานข้อมูล Firestore ของ projectId
ที่กําหนดค่าไว้สําหรับโปรแกรมจําลอง Firestore
RulesTestContext.firestore(settings?: Firestore.FirestoreSettings) => Firestore;
เมธอดนี้จะรับอินสแตนซ์ Firestore สําหรับบริบทการทดสอบนี้ อินสแตนซ์ Firebase JS Client SDK ที่แสดงผลสามารถใช้กับ API ของ SDK ของไคลเอ็นต์ (เวอร์ชัน 9 แบบโมดูลหรือเวอร์ชัน 9 ที่เข้ากันได้)
แสดงภาพการประเมินกฎ
โปรแกรมจำลอง Cloud Firestore ช่วยให้คุณเห็นภาพคําขอของไคลเอ็นต์ใน UI ของชุดโปรแกรมจำลอง รวมถึงการติดตามการประเมินสําหรับกฎความปลอดภัยของ Firebase
เปิดแท็บ Firestore > คำขอ เพื่อดูลำดับการประเมินโดยละเอียดสำหรับคำขอแต่ละรายการ
สร้างรายงานการทดสอบ
หลังจากใช้งานชุดการทดสอบแล้ว คุณจะเข้าถึงรายงานการครอบคลุมของการทดสอบที่แสดงวิธีประเมินกฎความปลอดภัยแต่ละข้อได้
หากต้องการดูรายงาน ให้ค้นหาปลายทางที่เปิดเผยในโปรแกรมจำลองขณะที่ทำงานอยู่ สำหรับเวอร์ชันที่เหมาะสำหรับเบราว์เซอร์ ให้ใช้ URL ต่อไปนี้:
http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage.html
ซึ่งจะแบ่งกฎออกเป็นนิพจน์และนิพจน์ย่อยที่คุณสามารถวางเมาส์เหนือเพื่อดูข้อมูลเพิ่มเติม รวมถึงจำนวนการประเมินและค่าที่แสดง สำหรับเวอร์ชันข้อมูลดิบ JSON ของข้อมูลนี้ ให้ใส่ URL ต่อไปนี้ในการค้นหา
http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage
ความแตกต่างระหว่างโปรแกรมจำลองและเวอร์ชันที่ใช้งานจริง
- คุณไม่จำเป็นต้องสร้างโปรเจ็กต์ Cloud Firestore อย่างชัดเจน โปรแกรมจำลองจะสร้างอินสแตนซ์ที่เข้าถึงโดยอัตโนมัติ
- โปรแกรมจำลอง Cloud Firestore ไม่ทำงานกับขั้นตอน Firebase Authentication ปกติ
แต่เรามีเมธอด
initializeTestApp()
ในไลบรารีrules-unit-testing
ของ Firebase Test SDK แทน ซึ่งใช้ฟิลด์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 อนุญาต/ปฏิเสธ เคสต่างๆ อย่างถูกต้อง