แม้ว่าการดำเนินการของไปป์ไลน์จะมีฟีเจอร์มากมาย แต่เครื่องมือกฎจะจำกัดให้จดจำตัวกรองการเปรียบเทียบ (เช่น >) และตรรกะ (เช่น or) เพื่อให้เป็นไปตามข้อจำกัดและความปลอดภัย
นิพจน์ตัวกรองที่รองรับ
เพื่อให้การดำเนินการของไปป์ไลน์ถูกจำกัดให้อยู่ในขอบเขตที่กฎกำหนดไว้ การดำเนินการดังกล่าวต้องใช้โอเปอเรเตอร์เชิงตรรกะและโอเปอเรเตอร์การเปรียบเทียบกับค่าคงที่ เครื่องมือสร้างกฎจะจดจำ ตัวกรองประเภทต่อไปนี้
- การเปรียบเทียบ:
eq,neq,gt,gte,lt,lte,in,arrayContains - ตรรกะ:
and,or
ตัวอย่างเช่น
where(eq("foo", 2))where(lt("foo", 2))documents("/user/1", "/user/2").where(...)
พร็อพเพอร์ตี้คำขอ
คุณยังคงใช้ออบเจ็กต์ request เพื่อตรวจสอบความถูกต้องของการตรวจสอบสิทธิ์และบริบทการค้นหาได้ แม้ว่าการดำเนินการไปป์ไลน์จะไม่รองรับพร็อพเพอร์ตี้บางรายการที่ใช้ได้ในการค้นหามาตรฐานก็ตาม
พร็อพเพอร์ตี้ที่รองรับ
เครื่องมือใหม่ยังคงรองรับพร็อพเพอร์ตี้ต่อไปนี้
request.auth: เข้าถึงข้อมูล UID และโทเค็นของผู้ใช้request.method: ระบุการดำเนินการ (เช่นget,list)request.path: เส้นทางของทรัพยากรที่มีการเข้าถึงrequest.time: การประทับเวลาฝั่งเซิร์ฟเวอร์ของคำขอ
พร็อพเพอร์ตี้ที่ไม่รองรับ
ระบบไม่รองรับพร็อพเพอร์ตี้ request.query เช่น limit, offset และ orderBy สำหรับการตรวจสอบกฎการดำเนินการไปป์ไลน์เนื่องจากความซับซ้อนในการกำหนดค่าเหล่านี้ในการค้นหาแบบหลายระดับ
การจัดการและสิทธิ์ในขั้นตอนไปป์ไลน์
มีขั้นตอนไปป์ไลน์ที่แตกต่างกันซึ่งแมปกับการดำเนินการแบบละเอียดที่เฉพาะเจาะจงในกฎความปลอดภัย ดังนี้
- สิทธิ์
allow list: ทริกเกอร์โดยระยะcollection(),collectionGroup()และdatabase() - สิทธิ์
allow get: ทริกเกอร์โดยระยะdocuments()ซึ่งได้รับการปฏิบัติคล้ายกับการดำเนินการgetแบบกลุ่ม - สิทธิ์
allow create: ทริกเกอร์โดยระยะinsert()และระยะupsert()เมื่อสร้างเอกสารใหม่ - สิทธิ์
allow update: ทริกเกอร์โดยขั้นตอนupdate()และขั้นตอนupsert()เมื่ออัปเดตเอกสารที่มีอยู่ - สิทธิ์
allow delete: ทริกเกอร์โดยระยะdelete() - สิทธิ์
allow write: มีผลกับการดำเนินการ DML ทั้งหมด (insert(),update(),upsert()และdelete()) - ระยะ Literals: ระยะ
literals()ไม่ได้อ่านจากฐานข้อมูล แต่อาจมีค่าใช้จ่าย เพื่อป้องกันการละเมิด ต้องจับคู่กับระยะอื่น (เช่นcollection()) ที่สามารถยืนยันได้ด้วยกฎ
ขั้นตอนการแก้ไขฟิลด์
กฎจะทำงานกับข้อมูลที่จัดเก็บไว้เท่านั้น ไม่ใช่ค่าที่ได้มา หากไปป์ไลน์มีขั้นตอนที่แก้ไขฟิลด์ (เช่น add_fields(...), replace_with(...), select(...), remove_fields(...)) เครื่องมือสร้างกฎจะหยุดใช้ข้อจำกัดของตัวกรองหลังจากพบขั้นตอนดังกล่าว เพื่อให้แน่ใจว่ากฎทำงานตามที่คาดไว้ ให้วางตำแหน่งขั้นตอนตัวกรอง (เช่น where) ไว้ก่อนขั้นตอนใดๆ ที่สามารถแก้ไขเอกสารที่จัดเก็บไว้เดิมได้
ตัวอย่างเช่น ลองดูกฎความปลอดภัยต่อไปนี้
match /databases/{database}/documents {
match /cities/{city} {
// Allow the user to read data if the document has the 'visibility'
// field set to 'public'
allow read: if resource.data.visibility == 'public';
}
}
ปฏิเสธ: กฎนี้จะปฏิเสธไปป์ไลน์ต่อไปนี้เนื่องจากระยะ addFields เกิดขึ้นก่อนการกรองเอกสารที่ visibility เป็น public:
const results = await db.pipeline()
.collection("/cities")
// Filters after a modification stage are ignored by Rules.
.addFields(constant(1000).as("population"))
.where(eq(field("visibility"), constant("public")))
.execute();
อนุญาต: กฎนี้อนุญาตไปป์ไลน์ต่อไปนี้เนื่องจากระยะ where(eq(field("visibility"), constant("public"))) เกิดขึ้นก่อนระยะการแก้ไขใดๆ
const results = await db.pipeline()
.collection("/cities")
.where(eq(field("visibility"), constant("public")))
.addFields(constant(1000).as("population"))
.execute();
ระยะของภาษาในการจัดการข้อมูลและกฎความปลอดภัย
เมื่อดำเนินการขั้นตอนภาษาในการจัดการข้อมูล (DML) (insert(), update(), upsert() และ delete()) กฎความปลอดภัยจะประเมินสิทธิ์แตกต่างจากการค้นหาเพื่ออ่าน ดังนี้
- การประเมินกฎต่อเอกสาร: การดำเนินการ DML จะประเมินกฎความปลอดภัยกับการเปลี่ยนแปลงเอกสารแต่ละรายการ ซึ่งแตกต่างจากไปป์ไลน์การอ่านที่ต้องใช้นิพจน์ตัวกรองล่วงหน้าเพื่อจำกัดการค้นหาในเวลาวางแผน
- ตัวแปรของกฎ
request.resource: มีข้อมูลเอกสารที่เสนอสำหรับการดำเนินการinsert(),update()และupsert()resource: มีข้อมูลเอกสารปัจจุบันที่จัดเก็บไว้ในฐานข้อมูลก่อนการแก้ไข (ใช้ได้กับupdate(),delete()และupsert()ของเอกสารที่มีอยู่)
ขีดจำกัดของระบบและลักษณะการทำงานของการดำเนินการด้วย DML
เมื่อเรียกใช้การดำเนินการ DML ด้วยกฎความปลอดภัย โปรดคำนึงถึงขีดจำกัดของระบบและลักษณะการทำงานต่อไปนี้
ขีดจำกัดการค้นหา 20 ครั้งใน get() และ exists()
กฎความปลอดภัยของ Firebase อนุญาตให้ค้นหาเอกสาร (get() หรือ exists()) ได้สูงสุด 20 รายการในคำขอทั้งหมด
เมื่อไปป์ไลน์ DML ทำงานนอกธุรกรรมที่ชัดเจน Cloud Firestore จะประมวลผลการเขียนเอกสารเป็นกลุ่ม เนื่องจากแต่ละกลุ่มจะดำเนินการในธุรกรรมของตนเอง และเอกสารอาจมีการแก้ไขพร้อมกันระหว่างกลุ่ม ระบบจึงจะประเมินกฎความปลอดภัยและการค้นหาเอกสารอีกครั้งสำหรับการเขียนแต่ละกลุ่ม
แม้ว่ากฎความปลอดภัยจะประเมินกับเอกสารแบบคงที่รายการเดียว (เช่น การตรวจสอบว่าผู้ใช้เป็นผู้ดูแลระบบหรือไม่) ให้ทำดังนี้
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /posts/{postId} {
allow write: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.isAdmin == true;
}
}
}
การเขียนแบบกลุ่มแต่ละชุดที่มีเอกสาร 10 รายการจะทำการค้นหา ด้วยเหตุนี้ หลังจากเขียนเอกสารที่เป็นไปได้ทั้งหมดแล้ว ระบบจะถึงขีดจำกัดการค้นหา 20 รายการสำหรับคำขอ และไปป์ไลน์จะล้มเหลวพร้อมข้อผิดพลาด PERMISSION_DENIED นอกจากนี้ การค้นหาแต่ละครั้งที่ดำเนินการต่อกลุ่มการเขียนจะทำให้เกิดการเรียกเก็บเงินสำหรับการอ่านของตัวเอง
สำเร็จบางส่วนและ PERMISSION_DENIED
เมื่อดำเนินการนอกธุรกรรม การดำเนินการ DML จะคอมมิตการเขียนเป็นกลุ่มตามลำดับ หากกลุ่มล้มเหลว ไม่ว่าจะเนื่องจากเอกสารไม่เป็นไปตามเงื่อนไขของกฎหรือเนื่องจากเกินขีดจำกัดการค้นหา 20 รายการ ไปป์ไลน์จะหยุดทำงานและแสดงข้อผิดพลาด PERMISSION_DENIED
อย่างไรก็ตาม ระบบจะไม่ย้อนกลับกลุ่มที่คอมมิตแล้ว ฐานข้อมูลจะยังคงอยู่ในสถานะอัปเดตบางส่วน เนื่องจากไคลเอ็นต์ได้รับข้อผิดพลาดโดยไม่มีรายการเอกสารที่แก้ไข คุณจึงต้องค้นหาข้อมูลเพื่อตรวจสอบว่าการเขียนใดสำเร็จ
การวินิจฉัยข้อผิดพลาดของกฎด้วยบันทึกการตรวจสอบระบบคลาวด์
ด้วยเหตุผลด้านความปลอดภัย ข้อผิดพลาด PERMISSION_DENIED ที่แสดงต่อไคลเอ็นต์จะไม่เปิดเผยว่าเงื่อนไขของกฎความปลอดภัยใดไม่สำเร็จ หรือมีการค้นหาถึงขีดจำกัด 20 ครั้งแล้วหรือไม่
หากต้องการวิเคราะห์การประเมินกฎที่ไม่สำเร็จ ผู้ดูแลระบบโปรเจ็กต์สามารถตรวจสอบบันทึกการตรวจสอบของ Cloud ในคอนโซล Google Cloud (ในส่วน Firestore > การตรวจสอบ หรือใน Logs Explorer) เพื่อดูรายการ EvaluationError โดยละเอียด