หน้านี้ต่อยอดจากแนวคิดใน
การกำหนดโครงสร้างกฎการรักษาความปลอดภัยและ
การเขียนเงื่อนไขสำหรับกฎการรักษาความปลอดภัยเพื่ออธิบายวิธี
กฎความปลอดภัยของ Cloud Firestore โต้ตอบกับการค้นหา ดูรายละเอียดวิธี
กฎความปลอดภัยจะมีผลต่อข้อความค้นหาที่คุณสามารถเขียนและอธิบายวิธีตรวจสอบให้แน่ใจว่า
จะใช้ข้อจำกัดเดียวกันกับกฎความปลอดภัยของคุณ หน้านี้และ
อธิบายวิธีเขียนกฎความปลอดภัยเพื่ออนุญาตหรือปฏิเสธการค้นหาตามคำค้นหา
ที่พักอย่างเช่น limit
และ orderBy
กฎไม่ใช่ตัวกรอง
เมื่อเขียนคำค้นหาเพื่อเรียกเอกสาร โปรดทราบว่ากฎความปลอดภัย ไม่ใช่ตัวกรอง คำค้นหาทั้งหมดมีหรือไม่มีเลย เพื่อช่วยคุณประหยัดเวลาและทรัพยากร Cloud Firestore จะประเมินการค้นหาเทียบกับชุดผลลัพธ์ที่เป็นไปได้ แทนค่าฟิลด์จริงสำหรับเอกสารทั้งหมดของคุณ ถ้าข้อความค้นหาสามารถ อาจแสดงเอกสารที่ไคลเอ็นต์ไม่มีสิทธิ์อ่าน คำขอทั้งหมดล้มเหลว
คำค้นหาและกฎความปลอดภัย
ดังที่แสดงในตัวอย่างด้านล่าง คุณต้องเขียนคำค้นหาให้พอดีกับ ข้อจำกัดของกฎความปลอดภัย
รักษาความปลอดภัยและค้นหาเอกสารตาม auth.uid
ตัวอย่างต่อไปนี้แสดงวิธีการเขียนคำค้นหาเพื่อเรียกเอกสาร
ได้รับการปกป้องด้วยกฎความปลอดภัย ลองพิจารณาฐานข้อมูลที่มีคอลเล็กชันของ
เอกสาร story
รายการ:
/stories/{storyid}
{
title: "A Great Story",
content: "Once upon a time...",
author: "some_auth_id",
published: false
}
นอกจากช่อง title
และ content
แล้ว เอกสารแต่ละรายการยังจัดเก็บฟิลด์
ช่อง author
และ published
ที่จะใช้สำหรับการควบคุมการเข้าถึง ตัวอย่างเหล่านี้จะถือว่า
แอปใช้การตรวจสอบสิทธิ์ของ Firebase เพื่อตั้งค่าช่อง author
ไปยัง UID ของผู้ใช้ที่สร้างเอกสาร Firebase
การตรวจสอบสิทธิ์ยังเติมค่าตัวแปร request.auth
ใน
กฎความปลอดภัย
กฎความปลอดภัยต่อไปนี้ใช้request.auth
และ
resource.data
ตัวแปรเพื่อจำกัดการเข้าถึงการอ่านและเขียนสำหรับแต่ละตัวแปร
story
ถึงผู้เขียน:
service cloud.firestore {
match /databases/{database}/documents {
match /stories/{storyid} {
// Only the authenticated user who authored the document can read or write
allow read, write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
สมมติว่าแอปของคุณมีหน้าเว็บที่แสดงรายการ story
แก่ผู้ใช้
ที่ตนเขียนไว้ คุณอาจคาดหวังว่าคุณสามารถใช้สิ่งต่อไปนี้
คำค้นหาเพื่อเติมข้อมูลในหน้านี้ อย่างไรก็ตาม การค้นหานี้จะล้มเหลวเนื่องจาก
ใส่ข้อจำกัดเดียวกันกับกฎความปลอดภัยของคุณ ดังนี้
ไม่ถูกต้อง: ข้อจำกัดในการค้นหาไม่ตรงกัน ข้อจำกัดของกฎความปลอดภัย
// This query will fail
db.collection("stories").get()
การค้นหาล้มเหลวแม้ว่าผู้ใช้ปัจจุบันจะเป็นผู้เขียนของทุกๆ
เอกสาร story
รายการ สาเหตุของการทำงานลักษณะนี้ก็คือเมื่อ
Cloud Firestore จะนำกฎความปลอดภัยไปใช้ โดยจะประเมินการค้นหา
เทียบกับชุดผลลัพธ์ที่เป็นไปได้ ไม่ใช่พร็อพเพอร์ตี้ตามจริงของ
ในฐานข้อมูลของคุณ หากการค้นหาอาจมีเอกสารอาจ
ที่ละเมิดกฎความปลอดภัยของคุณ การค้นหาจะล้มเหลว
ในทางกลับกัน ข้อความค้นหาต่อไปนี้ประสบความสำเร็จ เนื่องจากมี
ในช่อง author
เป็นกฎความปลอดภัย
ถูกต้อง: ข้อจำกัดของการค้นหาตรงกับค่าความปลอดภัย ข้อจำกัดเกี่ยวกับกฎ
var user = firebase.auth().currentUser;
db.collection("stories").where("author", "==", user.uid).get()
รักษาความปลอดภัยและค้นหาเอกสารตามฟิลด์
หากต้องการสาธิตการโต้ตอบระหว่างคำค้นหากับกฎเพิ่มเติม
กฎด้านล่างขยายสิทธิ์การอ่านสำหรับคอลเล็กชัน stories
เพื่อให้ผู้ใช้
อ่านเอกสาร story
รายการซึ่งตั้งค่าช่อง published
เป็น true
service cloud.firestore {
match /databases/{database}/documents {
match /stories/{storyid} {
// Anyone can read a published story; only story authors can read unpublished stories
allow read: if resource.data.published == true || (request.auth != null && request.auth.uid == resource.data.author);
// Only story authors can write
allow write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
การค้นหาสำหรับหน้าที่เผยแพร่ต้องมีข้อจำกัดเดียวกันกับการรักษาความปลอดภัย กฎ:
db.collection("stories").where("published", "==", true).get()
ข้อจำกัดในการค้นหา .where("published", "==", true)
รับประกันว่า
resource.data.published
เป็นtrue
สำหรับผลการค้นหาใดๆ ดังนั้น ข้อความค้นหานี้
เป็นไปตามกฎความปลอดภัยและได้รับอนุญาตให้อ่านข้อมูล
คำค้นหา OR
รายการ
เมื่อประเมินการค้นหา OR
เชิงตรรกะ (or
, in
หรือ array-contains-any
)
เทียบกับชุดกฎ Cloud Firestore จะประเมินค่าการเปรียบเทียบแต่ละค่า
แยกกัน ค่าการเปรียบเทียบแต่ละค่าต้องเป็นไปตามข้อจำกัดของกฎความปลอดภัย สำหรับ
ตัวอย่างเช่น สำหรับ
กฎต่อไปนี้
match /mydocuments/{doc} {
allow read: if resource.data.x > 5;
}
ไม่ถูกต้อง: คำค้นหาไม่ได้รับประกันว่า
x > 5
สำหรับเอกสารทั้งหมดที่เป็นไปได้
// These queries will fail
query(db.collection("mydocuments"),
or(where("x", "==", 1),
where("x", "==", 6)
)
)
query(db.collection("mydocuments"),
where("x", "in", [1, 3, 6, 42, 99])
)
ถูกต้อง: คำค้นหารับประกันว่า
x > 5
สำหรับเอกสารทั้งหมดที่เป็นไปได้
query(db.collection("mydocuments"),
or(where("x", "==", 6),
where("x", "==", 42)
)
)
query(db.collection("mydocuments"),
where("x", "in", [6, 42, 99, 105, 200])
)
การประเมินข้อจำกัดในคำค้นหา
กฎความปลอดภัยยังยอมรับหรือปฏิเสธการค้นหาตามข้อจำกัดได้
ตัวแปร request.query
ประกอบด้วย limit
, offset
และพร็อพเพอร์ตี้ orderBy
ของคำค้นหา เช่น กฎความปลอดภัย
สามารถปฏิเสธการค้นหาใดๆ ที่ไม่จำกัดจำนวนเอกสารสูงสุด
ดึงข้อมูลไปยังช่วงที่ระบุ:
allow list: if request.query.limit <= 10;
ชุดกฎต่อไปนี้แสดงวิธีเขียนกฎความปลอดภัยที่ประเมิน
ในข้อความค้นหา ตัวอย่างนี้ขยาย stories
ก่อนหน้า
ที่มีการเปลี่ยนแปลงต่อไปนี้
- ชุดกฎจะแยกกฎการอ่านออกเป็นกฎสำหรับ
get
และlist
- กฎ
get
จำกัดการเรียกเอกสารเดี่ยวๆ สำหรับเอกสารสาธารณะ หรือ เอกสารที่ผู้ใช้เขียน - กฎ
list
ใช้ข้อจำกัดเดียวกันกับget
แต่ใช้กับคำค้นหา ทั้งนี้ ตรวจสอบขีดจำกัดการค้นหา แล้วปฏิเสธการค้นหาแบบไม่จำกัด ขีดจำกัดมากกว่า 10 - ชุดกฎกำหนดฟังก์ชัน
authorOrPublished()
เพื่อหลีกเลี่ยงโค้ด การทำซ้ำ
service cloud.firestore {
match /databases/{database}/documents {
match /stories/{storyid} {
// Returns `true` if the requested story is 'published'
// or the user authored the story
function authorOrPublished() {
return resource.data.published == true || request.auth.uid == resource.data.author;
}
// Deny any query not limited to 10 or fewer documents
// Anyone can query published stories
// Authors can query their unpublished stories
allow list: if request.query.limit <= 10 &&
authorOrPublished();
// Anyone can retrieve a published story
// Only a story's author can retrieve an unpublished story
allow get: if authorOrPublished();
// Only a story's author can write to a story
allow write: if request.auth.uid == resource.data.author;
}
}
}
การค้นหาและกฎความปลอดภัยของกลุ่มคอลเล็กชัน
โดยค่าเริ่มต้น การค้นหาจะกำหนดขอบเขตไว้เป็นคอลเล็กชันเดียวและจะดึงผลลัพธ์กลับมา จากคอลเล็กชันนั้นเท่านั้น ด้วย การค้นหากลุ่มคอลเล็กชัน ดึงผลลัพธ์จากกลุ่มคอลเล็กชันที่ประกอบด้วยคอลเล็กชันทั้งหมดที่มีค่า รหัสเดียวกัน ส่วนนี้จะอธิบายวิธีรักษาความปลอดภัยของการค้นหากลุ่มคอลเล็กชัน โดยใช้กฎความปลอดภัย
รักษาความปลอดภัยและค้นหาเอกสารตามกลุ่มคอลเล็กชัน
ในกฎความปลอดภัย คุณต้องอนุญาต การค้นหากลุ่มคอลเล็กชันโดยการเขียนกฎสำหรับกลุ่มคอลเล็กชันดังนี้
- ตรวจสอบว่า
rules_version = '2';
เป็นบรรทัดแรกของชุดกฎ คอลเล็กชัน การค้นหากลุ่มจำเป็นต้องใช้ ลักษณะการทำงานของไวลด์การ์ดซ้ำ{name=**}
แบบใหม่ของการรักษาความปลอดภัย กฎเวอร์ชัน 2 - เขียนกฎสำหรับกลุ่มคอลเล็กชันของคุณโดยใช้
match /{path=**}/[COLLECTION_ID]/{doc}
.
ตัวอย่างเช่น พิจารณาฟอรัมที่จัดเป็นเอกสาร forum
ฉบับที่มี
posts
คอลเล็กชันย่อย:
/forums/{forumid}/posts/{postid}
{
author: "some_auth_id",
authorname: "some_username",
content: "I just read a great story.",
}
ในแอปพลิเคชันนี้ เราทำให้โพสต์ต่างๆ สามารถแก้ไขได้โดยเจ้าของ และอ่านได้โดย ผู้ใช้ที่ตรวจสอบสิทธิ์แล้ว:
service cloud.firestore {
match /databases/{database}/documents {
match /forums/{forumid}/posts/{post} {
// Only authenticated users can read
allow read: if request.auth != null;
// Only the post author can write
allow write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
ผู้ใช้ที่ได้รับการตรวจสอบสิทธิ์จะเรียกดูโพสต์ของฟอรัมใดก็ได้ ดังนี้
db.collection("forums/technology/posts").get()
แต่หากต้องการแสดงโพสต์ของผู้ใช้ปัจจุบันในทุกฟอรัม
คุณสามารถใช้การค้นหากลุ่มคอลเล็กชันเพื่อดึงข้อมูล
ผลลัพธ์จากคอลเล็กชันทั้งหมด posts
รายการ:
var user = firebase.auth().currentUser;
db.collectionGroup("posts").where("author", "==", user.uid).get()
ในกฎความปลอดภัยของคุณ คุณจะต้องอนุญาตการค้นหานี้โดย
เขียนกฎการอ่านหรือรายการสำหรับกลุ่มคอลเล็กชัน posts
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Authenticated users can query the posts collection group
// Applies to collection queries, collection group queries, and
// single document retrievals
match /{path=**}/posts/{post} {
allow read: if request.auth != null;
}
match /forums/{forumid}/posts/{postid} {
// Only a post's author can write to a post
allow write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
อย่างไรก็ตาม โปรดทราบว่ากฎเหล่านี้จะมีผลกับคอลเล็กชันทั้งหมดที่มีรหัส posts
โดยไม่คำนึงถึงลำดับชั้น ตัวอย่างเช่น กฎเหล่านี้จะใช้กับทุกข้อต่อไปนี้
posts
คอลเล็กชัน:
/posts/{postid}
/forums/{forumid}/posts/{postid}
/forums/{forumid}/subforum/{subforumid}/posts/{postid}
การค้นหากลุ่มคอลเล็กชันที่ปลอดภัยที่อิงจากช่อง
เช่นเดียวกับการค้นหาคอลเล็กชันเดียว การค้นหากลุ่มคอลเล็กชันต้องเป็นไปตาม
ที่จำกัดไว้โดยกฎความปลอดภัยของคุณ เช่น เราสามารถเพิ่ม published
ในแต่ละโพสต์ในฟอรัมเหมือนที่เราทำในตัวอย่าง stories
ด้านบน
/forums/{forumid}/posts/{postid}
{
author: "some_auth_id",
authorname: "some_username",
content: "I just read a great story.",
published: false
}
จากนั้นเราสามารถเขียนกฎสำหรับกลุ่มคอลเล็กชัน posts
ตาม
สถานะ published
และโพสต์ author
:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Returns `true` if the requested post is 'published'
// or the user authored the post
function authorOrPublished() {
return resource.data.published == true || request.auth.uid == resource.data.author;
}
match /{path=**}/posts/{post} {
// Anyone can query published posts
// Authors can query their unpublished posts
allow list: if authorOrPublished();
// Anyone can retrieve a published post
// Authors can retrieve an unpublished post
allow get: if authorOrPublished();
}
match /forums/{forumid}/posts/{postid} {
// Only a post's author can write to a post
allow write: if request.auth.uid == resource.data.author;
}
}
}
เมื่อใช้กฎเหล่านี้ ไคลเอ็นต์บนเว็บ, Apple และ Android จะสามารถสร้างคำค้นหาต่อไปนี้ได้
ทุกคนสามารถเรียกดูโพสต์ที่เผยแพร่ในฟอรัมได้ดังนี้
db.collection("forums/technology/posts").where('published', '==', true).get()
ทุกคนสามารถเรียกดูโพสต์ที่เผยแพร่ของผู้เขียนในทุกฟอรัม
db.collectionGroup("posts").where("author", "==", "some_auth_id").where('published', '==', true).get()
ผู้เขียนสามารถเรียกดูโพสต์ทั้งหมดที่เผยแพร่แล้วและไม่ได้เผยแพร่ทั้งหมด ฟอรัม:
var user = firebase.auth().currentUser; db.collectionGroup("posts").where("author", "==", user.uid).get()
รักษาความปลอดภัยและค้นหาเอกสารตามกลุ่มคอลเล็กชันและเส้นทางของเอกสาร
ในบางกรณี คุณอาจต้องการจำกัดการค้นหากลุ่มคอลเล็กชันตาม เส้นทางเอกสาร หากต้องการสร้างข้อจำกัดเหล่านี้ คุณสามารถใช้เทคนิคเดียวกันนี้สำหรับ การรักษาความปลอดภัยและการค้นหาเอกสารตามฟิลด์
ลองใช้แอปพลิเคชันที่ติดตามธุรกรรมของผู้ใช้แต่ละราย ในตลาดหลักทรัพย์และคริปโตเคอเรนซีหลายแห่ง:
/users/{userid}/Exchange/{exchangeid}/transactions/{transaction}
{
amount: 100,
exchange: 'some_exchange_name',
timestamp: April 1, 2019 at 12:00:00 PM UTC-7,
user: "some_auth_id",
}
โปรดสังเกตช่อง user
แม้ว่าเราจะทราบว่าผู้ใช้คนใดเป็นเจ้าของ transaction
เอกสารจากเส้นทางของเอกสาร เราทำซ้ำข้อมูลนี้ในแต่ละ
transaction
เนื่องจากช่วยให้เราทำได้ 2 อย่าง ดังนี้
เขียนการค้นหากลุ่มคอลเล็กชันที่จำกัดไว้สำหรับเอกสารที่มี
/users/{userid}
ที่เฉพาะเจาะจงในเส้นทางเอกสาร เช่นvar user = firebase.auth().currentUser; // Return current user's last five transactions across all exchanges db.collectionGroup("transactions").where("user", "==", user).orderBy('timestamp').limit(5)
บังคับใช้ข้อจำกัดนี้สำหรับการค้นหาทั้งหมดในคอลเล็กชัน
transactions
เพื่อไม่ให้ผู้ใช้รายหนึ่งไม่สามารถเรียกเอกสารtransaction
ของผู้ใช้รายอื่นได้
เราบังคับใช้ข้อจำกัดนี้ในกฎความปลอดภัยและรวมการตรวจสอบข้อมูล
สำหรับฟิลด์ user
:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{path=**}/transactions/{transaction} {
// Authenticated users can retrieve only their own transactions
allow read: if resource.data.user == request.auth.uid;
}
match /users/{userid}/exchange/{exchangeid}/transactions/{transaction} {
// Authenticated users can write to their own transactions subcollections
// Writes must populate the user field with the correct auth id
allow write: if userid == request.auth.uid && request.data.user == request.auth.uid
}
}
}
ขั้นตอนถัดไป
- ดูตัวอย่างโดยละเอียดเพิ่มเติมเกี่ยวกับการควบคุมการเข้าถึงตามบทบาทได้ที่การรักษาความปลอดภัยข้อมูล สิทธิ์เข้าถึงสำหรับผู้ใช้และกลุ่ม
- โปรดอ่านข้อมูลอ้างอิงกฎความปลอดภัย