คู่มือนี้สร้างจากคำแนะนำเกี่ยวกับ การจัดโครงสร้างกฎความปลอดภัย เพื่อแสดงวิธีเพิ่มเงื่อนไขให้กับกฎความปลอดภัยของ Cloud Firestore ของคุณ หากคุณไม่คุ้นเคยกับพื้นฐานของกฎความปลอดภัยของ Cloud Firestore โปรดดูคู่มือ การเริ่มต้นใช้ งาน
โครงสร้างหลักของกฎความปลอดภัยของ Cloud Firestore คือเงื่อนไข เงื่อนไขคือนิพจน์บูลีนที่กำหนดว่าการดำเนินการใดควรได้รับอนุญาตหรือปฏิเสธ ใช้กฎความปลอดภัยเพื่อเขียนเงื่อนไขที่ตรวจสอบการรับรองความถูกต้องของผู้ใช้ ตรวจสอบข้อมูลขาเข้า หรือแม้แต่เข้าถึงส่วนอื่นๆ ของฐานข้อมูลของคุณ
การรับรองความถูกต้อง
รูปแบบกฎความปลอดภัยที่พบบ่อยที่สุดรูปแบบหนึ่งคือการควบคุมการเข้าถึงตามสถานะการตรวจสอบสิทธิ์ของผู้ใช้ ตัวอย่างเช่น แอปของคุณอาจต้องการอนุญาตให้เฉพาะผู้ใช้ที่ลงชื่อเข้าใช้เท่านั้นที่สามารถเขียนข้อมูลได้:
service cloud.firestore {
match /databases/{database}/documents {
// Allow the user to access documents in the "cities" collection
// only if they are authenticated.
match /cities/{city} {
allow read, write: if request.auth != null;
}
}
}
รูปแบบทั่วไปอีกประการหนึ่งคือเพื่อให้แน่ใจว่าผู้ใช้สามารถอ่านและเขียนข้อมูลของตนเองได้เท่านั้น:
service cloud.firestore {
match /databases/{database}/documents {
// Make sure the uid of the requesting user matches name of the user
// document. The wildcard expression {userId} makes the userId variable
// available in rules.
match /users/{userId} {
allow read, update, delete: if request.auth != null && request.auth.uid == userId;
allow create: if request.auth != null;
}
}
}
หากแอปของคุณใช้ Firebase Authentication หรือ Google Cloud Identity Platform ตัวแปร request.auth
จะมีข้อมูลการตรวจสอบสิทธิ์สำหรับไคลเอ็นต์ที่ขอข้อมูล สำหรับข้อมูลเพิ่มเติมเกี่ยวกับ request.auth
โปรดดู เอกสารอ้างอิง
การตรวจสอบข้อมูล
แอพจำนวนมากจัดเก็บข้อมูลการควบคุมการเข้าถึงเป็นช่องในเอกสารในฐานข้อมูล กฎความปลอดภัยของ Cloud Firestore สามารถอนุญาตหรือปฏิเสธการเข้าถึงแบบไดนามิกโดยอิงตามข้อมูลเอกสาร:
service cloud.firestore {
match /databases/{database}/documents {
// Allow the user to read data if the document has the 'visibility'
// field set to 'public'
match /cities/{city} {
allow read: if resource.data.visibility == 'public';
}
}
}
ตัวแปร resource
อ้างอิงถึงเอกสารที่ร้องขอ และ resource.data
คือแผนผังของฟิลด์และค่าทั้งหมดที่จัดเก็บไว้ในเอกสาร สำหรับข้อมูลเพิ่มเติมเกี่ยวกับตัวแปร resource
โปรดดู เอกสารอ้างอิง
เมื่อเขียนข้อมูล คุณอาจต้องการเปรียบเทียบข้อมูลขาเข้ากับข้อมูลที่มีอยู่ ในกรณีนี้ หากชุดกฎของคุณอนุญาตให้มีการเขียนที่รอดำเนินการ ตัวแปร request.resource
จะมีสถานะในอนาคตของเอกสาร สำหรับการดำเนินการ update
ที่แก้ไขเฉพาะชุดย่อยของฟิลด์เอกสาร request.resource
จะมีสถานะเอกสารที่ค้างอยู่หลังการดำเนินการ คุณสามารถตรวจสอบค่าฟิลด์ใน request.resource
เพื่อป้องกันการอัปเดตข้อมูลที่ไม่ต้องการหรือไม่สอดคล้องกัน:
service cloud.firestore {
match /databases/{database}/documents {
// Make sure all cities have a positive population and
// the name is not changed
match /cities/{city} {
allow update: if request.resource.data.population > 0
&& request.resource.data.name == resource.data.name;
}
}
}
เข้าถึงเอกสารอื่นๆ
การใช้ฟังก์ชัน get()
และ exists()
กฎความปลอดภัยของคุณสามารถประเมินคำขอขาเข้าเทียบกับเอกสารอื่นๆ ในฐานข้อมูลได้ ฟังก์ชั่น get()
และ exists()
ทั้งคู่คาดหวังเส้นทางเอกสารที่ระบุอย่างครบถ้วน เมื่อใช้ตัวแปรเพื่อสร้างเส้นทางสำหรับ get()
และ exists()
คุณจะต้องหลีกเลี่ยงตัวแปรอย่างชัดเจนโดยใช้ไวยากรณ์ $(variable)
ในตัวอย่างด้านล่าง ตัวแปร database
ถูกจับโดยคำสั่งการจับ match /databases/{database}/documents
และใช้เพื่อสร้างเส้นทาง:
service cloud.firestore {
match /databases/{database}/documents {
match /cities/{city} {
// Make sure a 'users' document exists for the requesting user before
// allowing any writes to the 'cities' collection
allow create: if request.auth != null && exists(/databases/$(database)/documents/users/$(request.auth.uid))
// Allow the user to delete cities if their user document has the
// 'admin' field set to 'true'
allow delete: if request.auth != null && get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin == true
}
}
}
สำหรับการเขียน คุณสามารถใช้ฟังก์ชัน getAfter()
เพื่อเข้าถึงสถานะของเอกสารหลังจากธุรกรรมหรือชุดการเขียนเสร็จสมบูรณ์ แต่ก่อนที่ธุรกรรมหรือชุดการดำเนินการจะกระทำ เช่นเดียวกับ get()
ฟังก์ชัน getAfter()
รับเส้นทางเอกสารที่ระบุอย่างครบถ้วน คุณสามารถใช้ getAfter()
เพื่อกำหนดชุดการเขียนที่ต้องเกิดขึ้นร่วมกันเป็นธุรกรรมหรือเป็นชุด
เข้าถึงขีดจำกัดการโทร
มีการจำกัดการเรียกเข้าถึงเอกสารต่อการประเมินชุดกฎ:
- 10 สำหรับคำขอเอกสารเดี่ยวและคำขอแบบสอบถาม
20 สำหรับการอ่านหลายเอกสาร ธุรกรรม และการเขียนแบบเป็นชุด ขีดจำกัดก่อนหน้านี้คือ 10 ยังใช้กับแต่ละการดำเนินการด้วย
ตัวอย่างเช่น ลองจินตนาการว่าคุณสร้างคำขอเขียนเป็นชุดโดยมีการดำเนินการเขียน 3 ครั้ง และกฎความปลอดภัยของคุณใช้การเรียกเข้าถึงเอกสาร 2 ครั้งเพื่อตรวจสอบความถูกต้องของการเขียนแต่ละครั้ง ในกรณีนี้ การเขียนแต่ละครั้งจะใช้การเรียกเข้าถึง 2 ครั้งจาก 10 ครั้ง และคำขอการเขียนแบบแบตช์ใช้การเรียกการเข้าถึง 6 ครั้งจาก 20 ครั้ง
เกินขีดจำกัดอย่างใดอย่างหนึ่งส่งผลให้เกิดข้อผิดพลาดในการปฏิเสธสิทธิ์ การเรียกเข้าถึงเอกสารบางรายการอาจถูกแคช และการเรียกที่แคชไว้จะไม่นับรวมในขีดจำกัด
สำหรับคำอธิบายโดยละเอียดว่าขีดจำกัดเหล่านี้ส่งผลต่อธุรกรรมและการเขียนแบบเป็นชุดอย่างไร โปรดดูคำแนะนำสำหรับ การรักษาความปลอดภัยการดำเนินการแบบอะตอมมิก
เข้าถึงการโทรและราคา
การใช้ฟังก์ชันเหล่านี้จะดำเนินการอ่านในฐานข้อมูลของคุณ ซึ่งหมายความว่าคุณจะถูกเรียกเก็บเงินสำหรับการอ่านเอกสาร แม้ว่ากฎของคุณจะปฏิเสธคำขอก็ตาม ดู ราคา Cloud Firestore สำหรับข้อมูลการเรียกเก็บเงินที่เฉพาะเจาะจงมากขึ้น
ฟังก์ชั่นที่กำหนดเอง
เนื่องจากกฎความปลอดภัยของคุณมีความซับซ้อนมากขึ้น คุณอาจต้องการรวมชุดเงื่อนไขไว้ในฟังก์ชันที่คุณสามารถนำมาใช้ซ้ำได้ทั่วทั้งชุดกฎของคุณ กฎความปลอดภัยรองรับฟังก์ชันแบบกำหนดเอง ไวยากรณ์สำหรับฟังก์ชันแบบกำหนดเองจะคล้ายกับ JavaScript เล็กน้อย แต่ฟังก์ชันกฎความปลอดภัยจะเขียนในภาษาเฉพาะโดเมนซึ่งมีข้อจำกัดที่สำคัญบางประการ:
- ฟังก์ชันสามารถมีคำสั่ง
return
ได้เพียงคำสั่งเดียว ไม่สามารถมีตรรกะเพิ่มเติมใดๆ ได้ ตัวอย่างเช่น ไม่สามารถดำเนินการวนซ้ำหรือเรียกใช้บริการภายนอกได้ - ฟังก์ชันต่างๆ สามารถเข้าถึงฟังก์ชันและตัวแปรจากขอบเขตที่กำหนดไว้ได้โดยอัตโนมัติ ตัวอย่างเช่น ฟังก์ชันที่กำหนดภายในขอบเขต
service cloud.firestore
มีสิทธิ์เข้าถึงตัวแปรresource
และฟังก์ชันในตัว เช่นget()
และexists()
- ฟังก์ชันอาจเรียกใช้ฟังก์ชันอื่นแต่อาจไม่เรียกซ้ำ ความลึกของสแต็กการโทรทั้งหมดถูกจำกัดไว้ที่ 10
- ในกฎเวอร์ชัน
v2
ฟังก์ชันสามารถกำหนดตัวแปรโดยใช้คีย์เวิร์ดlet
ฟังก์ชันสามารถผูก Let ได้สูงสุด 10 รายการ แต่ต้องลงท้ายด้วยคำสั่ง Return
ฟังก์ชันถูกกำหนดด้วยคีย์เวิร์ดของ function
และรับอาร์กิวเมนต์เป็นศูนย์หรือมากกว่า ตัวอย่างเช่น คุณอาจต้องการรวมเงื่อนไขสองประเภทที่ใช้ในตัวอย่างด้านบนเป็นฟังก์ชันเดียว:
service cloud.firestore {
match /databases/{database}/documents {
// True if the user is signed in or the requested data is 'public'
function signedInOrPublic() {
return request.auth.uid != null || resource.data.visibility == 'public';
}
match /cities/{city} {
allow read, write: if signedInOrPublic();
}
match /users/{user} {
allow read, write: if signedInOrPublic();
}
}
}
การใช้ฟังก์ชันต่างๆ ในกฎความปลอดภัยจะทำให้สามารถดูแลรักษาได้มากขึ้นเมื่อกฎของคุณมีความซับซ้อนมากขึ้น
กฎไม่ใช่ตัวกรอง
เมื่อคุณรักษาความปลอดภัยข้อมูลของคุณและเริ่มเขียนแบบสอบถามแล้ว โปรดทราบว่ากฎความปลอดภัยไม่ใช่ตัวกรอง คุณไม่สามารถเขียนคำค้นหาสำหรับเอกสารทั้งหมดในคอลเล็กชันได้ และคาดว่า Cloud Firestore จะส่งคืนเฉพาะเอกสารที่ไคลเอ็นต์ปัจจุบันมีสิทธิ์ในการเข้าถึง
ตัวอย่างเช่น ใช้กฎความปลอดภัยต่อไปนี้:
service cloud.firestore {
match /databases/{database}/documents {
// Allow the user to read data if the document has the 'visibility'
// field set to 'public'
match /cities/{city} {
allow read: if resource.data.visibility == 'public';
}
}
}
ปฏิเสธ : กฎนี้ปฏิเสธแบบสอบถามต่อไปนี้เนื่องจากชุดผลลัพธ์สามารถรวมเอกสารที่ visibility
ไม่เป็น public
:
เว็บ
db.collection("cities").get() .then(function(querySnapshot) { querySnapshot.forEach(function(doc) { console.log(doc.id, " => ", doc.data()); }); });
อนุญาต : กฎนี้อนุญาตให้มีการสืบค้นต่อไปนี้เนื่องจากส่วนคำสั่ง where("visibility", "==", "public")
รับประกันว่าชุดผลลัพธ์จะเป็นไปตามเงื่อนไขของกฎ:
เว็บ
db.collection("cities").where("visibility", "==", "public").get() .then(function(querySnapshot) { querySnapshot.forEach(function(doc) { console.log(doc.id, " => ", doc.data()); }); });
กฎความปลอดภัยของ Cloud Firestore จะประเมินแต่ละคำค้นหาโดยเทียบกับผลลัพธ์ที่เป็นไปได้ และล้มเหลวในการร้องขอหากสามารถส่งคืนเอกสารที่ไคลเอ็นต์ไม่มีสิทธิ์ในการอ่าน ข้อความค้นหาต้องเป็นไปตามข้อจำกัดที่กำหนดโดยกฎความปลอดภัยของคุณ สำหรับข้อมูลเพิ่มเติมเกี่ยวกับกฎความปลอดภัยและการสืบค้น โปรดดู ข้อมูลการสืบค้นอย่างปลอดภัย
ขั้นตอนถัดไป
- เรียนรู้ว่า กฎความปลอดภัยส่งผลต่อคำถามของคุณ อย่างไร
- เรียนรู้วิธี จัดโครงสร้างกฎความปลอดภัย
- อ่าน การอ้างอิงกฎความปลอดภัย
- สำหรับแอปของคุณที่ใช้ Cloud Storage สำหรับ Firebase โปรดเรียนรู้วิธี เขียนเงื่อนไขกฎความปลอดภัยของ Cloud Storage ที่เข้าถึงเอกสาร Cloud Firestore