ความปลอดภัยเป็นหนึ่งในชิ้นส่วนที่ยากที่สุดของการพัฒนาแอป ในแอปพลิเคชันส่วนใหญ่ นักพัฒนาแอปต้องสร้างและเรียกใช้เซิร์ฟเวอร์ที่จัดการการตรวจสอบสิทธิ์ (ผู้ใช้เป็นใคร) และการให้สิทธิ์ (สิ่งที่ผู้ใช้ทําได้)
Firebase Security Rules นำเลเยอร์กลาง (เซิร์ฟเวอร์) ออกและให้คุณระบุสิทธิ์ตามเส้นทางสำหรับไคลเอ็นต์ที่เชื่อมต่อกับข้อมูลโดยตรง ใช้คู่มือนี้เพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีใช้กฎกับคำขอขาเข้า
เลือกผลิตภัณฑ์เพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับกฎของผลิตภัณฑ์
Cloud Firestore
โครงสร้างพื้นฐาน
Firebase Security Rules ใน Cloud Firestore และ Cloud Storage ใช้โครงสร้างและไวยากรณ์ต่อไปนี้
service <<name>> {
// Match the resource path.
match <<path>> {
// Allow the request if the following conditions are true.
allow <<methods>> : if <<condition>>
}
}
แนวคิดสําคัญต่อไปนี้เป็นแนวคิดที่คุณควรเข้าใจเมื่อสร้างกฎ
- คําขอ: เมธอดที่เรียกใช้ในคำสั่ง
allow
นี่เป็นเมธอดที่คุณอนุญาตให้ทํางาน วิธีการมาตรฐาน ได้แก่get
,list
,create
,update
และdelete
เมธอดที่สะดวกread
และwrite
ช่วยเปิดใช้สิทธิ์การอ่านและเขียนแบบกว้างในฐานข้อมูลหรือเส้นทางพื้นที่เก็บข้อมูลที่ระบุ - เส้นทาง: ฐานข้อมูลหรือตำแหน่งที่จัดเก็บ ซึ่งแสดงเป็นเส้นทาง URI
- กฎ: คำสั่ง
allow
ซึ่งมีเงื่อนไขที่อนุญาตคำขอหากประเมินค่าเป็น "จริง"
กฎความปลอดภัยเวอร์ชัน 2
ในเดือนพฤษภาคม 2019 กฎความปลอดภัย Firebase เวอร์ชัน 2 พร้อมใช้งานแล้ว กฎเวอร์ชัน 2 จะเปลี่ยนลักษณะการทำงานของไวลด์การ์ดแบบย้อนกลับ {name=**}
คุณต้องใช้เวอร์ชัน 2 หากมีแผนที่จะใช้การค้นหากลุ่มคอลเล็กชัน คุณต้องเลือกใช้เวอร์ชัน 2 โดยทำให้ rules_version = '2';
เป็นบรรทัดแรกในกฎการรักษาความปลอดภัย
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
เส้นทางที่ตรงกัน
คำสั่งการจับคู่ทั้งหมดควรชี้ไปยังเอกสาร ไม่ใช่คอลเล็กชัน คำสั่งการจับคู่สามารถชี้ไปยังเอกสารที่เฉพาะเจาะจง เช่น match /cities/SF
หรือใช้ไวลด์การ์ดเพื่อชี้ไปยังเอกสารใดก็ได้ในเส้นทางที่ระบุ เช่น match /cities/{city}
ในตัวอย่างข้างต้น คำสั่งการทํางานแบบตรงทั้งหมดใช้ไวยากรณ์ไวลด์การ์ด {city}
ซึ่งหมายความว่ากฎจะมีผลกับเอกสารทุกรายการในคอลเล็กชัน cities
เช่น /cities/SF
หรือ /cities/NYC
เมื่อประเมินนิพจน์ allow
ในคำสั่งการจับคู่แล้ว ตัวแปร city
จะเปลี่ยนเป็นชื่อเอกสารเมือง เช่น SF
หรือ NYC
คอลเล็กชันย่อยที่ตรงกัน
ข้อมูลใน Cloud Firestore จะจัดระเบียบเป็นคอลเล็กชันเอกสาร และเอกสารแต่ละรายการอาจขยายลําดับชั้นผ่านคอลเล็กชันย่อย คุณจำเป็นต้องเข้าใจวิธีที่กฎการรักษาความปลอดภัยโต้ตอบกับข้อมูลลําดับชั้น
ลองพิจารณาสถานการณ์ที่เอกสารแต่ละรายการในคอลเล็กชัน cities
มีคอลเล็กชันย่อย landmarks
กฎความปลอดภัยจะมีผลเฉพาะกับเส้นทางที่ตรงกันเท่านั้น ดังนั้นการควบคุมการเข้าถึงที่กําหนดไว้ในคอลเล็กชัน cities
จึงไม่มีผลกับคอลเล็กชันย่อย landmarks
แต่ให้เขียนกฎที่ชัดเจนเพื่อควบคุมการเข้าถึงคอลเล็กชันย่อยแทน ดังนี้
service cloud.firestore {
match /databases/{database}/documents {
match /cities/{city} {
allow read, write: if <condition>;
// Explicitly define rules for the 'landmarks' subcollection
match /landmarks/{landmark} {
allow read, write: if <condition>;
}
}
}
}
เมื่อฝังคำสั่ง match
เส้นทางของคำสั่ง match
ภายในจะสัมพันธ์กับเส้นทางของคำสั่ง match
ภายนอกเสมอ ดังนั้นชุดกฎต่อไปนี้จึงมีความหมายเหมือนกัน
service cloud.firestore {
match /databases/{database}/documents {
match /cities/{city} {
match /landmarks/{landmark} {
allow read, write: if <condition>;
}
}
}
}
service cloud.firestore {
match /databases/{database}/documents {
match /cities/{city}/landmarks/{landmark} {
allow read, write: if <condition>;
}
}
}
ไวลด์การ์ดแบบย้อนกลับ
หากต้องการให้กฎมีผลกับลําดับชั้นที่ลึกตามต้องการ ให้ใช้ไวยากรณ์ไวลด์การ์ดแบบซ้ำซ้อน {name=**}
ดังนี้
service cloud.firestore {
match /databases/{database}/documents {
// Matches any document in the cities collection as well as any document
// in a subcollection.
match /cities/{document=**} {
allow read, write: if <condition>;
}
}
}
เมื่อใช้ไวยากรณ์ไวลด์การ์ดแบบเรียกซ้ำ ตัวแปรไวลด์การ์ดจะมีกลุ่มเส้นทางที่ตรงกันทั้งหมด แม้ว่าเอกสารจะอยู่ในคอลเล็กชันย่อยที่ฝังอยู่ลึก ตัวอย่างเช่น กฎที่แสดงข้างต้นจะจับคู่กับเอกสารที่อยู่ใน /cities/SF/landmarks/coit_tower
และค่าของตัวแปร document
จะเป็น SF/landmarks/coit_tower
อย่างไรก็ตาม โปรดทราบว่าลักษณะการทํางานของไวลด์การ์ดแบบย้อนกลับจะขึ้นอยู่กับเวอร์ชันของกฎ
เวอร์ชัน 1
กฎความปลอดภัยจะใช้เวอร์ชัน 1 โดยค่าเริ่มต้น ในเวอร์ชัน 1 อักขระไวลด์การ์ดแบบย้อนกลับจะจับคู่กับรายการเส้นทางอย่างน้อย 1 รายการ รายการเหล่านี้จะไม่ตรงกับเส้นทางว่าง ดังนั้น match /cities/{city}/{document=**}
จะตรงกับเอกสารในคอลเล็กชันย่อยแต่ไม่ตรงกับในคอลเล็กชัน cities
ส่วน match /cities/{document=**}
จะตรงกับทั้งเอกสารในคอลเล็กชัน cities
และคอลเล็กชันย่อย
ไวลด์การ์ดแบบย้อนกลับต้องอยู่ท้ายคำสั่งการจับคู่
เวอร์ชัน 2
ในกฎความปลอดภัยเวอร์ชัน 2 ไวลด์การ์ดแบบย้อนกลับจะจับคู่รายการเส้นทางตั้งแต่ 0 รายการขึ้นไป match/cities/{city}/{document=**}
จะจับคู่กับเอกสารในคอลเล็กชันย่อยใดก็ได้ รวมถึงเอกสารในคอลเล็กชัน cities
คุณต้องเลือกใช้เวอร์ชัน 2 โดยเพิ่ม rules_version = '2';
ที่ด้านบนของกฎความปลอดภัย
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Matches any document in the cities collection as well as any document
// in a subcollection.
match /cities/{city}/{document=**} {
allow read, write: if <condition>;
}
}
}
คุณมีไวลด์การ์ดแบบย้อนกลับได้สูงสุด 1 รายการต่อคำสั่งการจับคู่ แต่เวอร์ชัน 2 คุณจะวางไวลด์การ์ดนี้ไว้ที่ใดก็ได้ในคำสั่งการจับคู่ เช่น
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Matches any document in the songs collection group
match /{path=**}/songs/{song} {
allow read, write: if <condition>;
}
}
}
หากใช้การค้นหากลุ่มคอลเล็กชัน คุณต้องใช้เวอร์ชัน 2 โปรดดูการรักษาความปลอดภัยให้กับการค้นหากลุ่มคอลเล็กชัน
คำสั่งการจับคู่ที่ทับซ้อนกัน
เอกสารอาจตรงกับmatch
คำสั่งมากกว่า 1 รายการ ในกรณีที่นิพจน์ allow
หลายรายการตรงกับคําขอ ระบบจะอนุญาตการเข้าถึงหากเงื่อนไขใดหนึ่งเป็น true
ดังนี้
service cloud.firestore {
match /databases/{database}/documents {
// Matches any document in the 'cities' collection.
match /cities/{city} {
allow read, write: if false;
}
// Matches any document in the 'cities' collection or subcollections.
match /cities/{document=**} {
allow read, write: if true;
}
}
}
ในตัวอย่างข้างต้น ระบบจะอนุญาตการอ่านและการเขียนทั้งหมดในคอลเล็กชัน cities
เนื่องจากกฎที่ 2 เป็น true
เสมอ แม้ว่ากฎที่ 1 จะเป็น false
เสมอก็ตาม
ขีดจํากัดของกฎความปลอดภัย
โปรดคำนึงถึงขีดจำกัดต่อไปนี้เมื่อใช้กฎความปลอดภัย
ขีดจำกัด | รายละเอียด |
---|---|
จำนวนการเรียกใช้ exists() , get() และ getAfter() สูงสุดต่อคำขอ |
หากเกินขีดจำกัดดังกล่าว ระบบจะแสดงข้อผิดพลาด "ถูกปฏิเสธสิทธิ์" ระบบอาจแคชการเรียกใช้การเข้าถึงเอกสารบางรายการไว้ และการเรียกใช้ที่แคชไว้จะไม่นับรวมในขีดจำกัด |
ความลึกสูงสุดของคำสั่ง match ที่ฝังอยู่ |
10 |
ความยาวเส้นทางสูงสุดในส่วนเส้นทางที่อนุญาตภายในชุดคำสั่ง match ที่ฝังอยู่ |
100 |
จํานวนตัวแปรการบันทึกเส้นทางสูงสุดที่อนุญาตภายในชุดคำสั่ง match ที่ฝังอยู่ |
20 |
ความลึกสูงสุดของการเรียกใช้ฟังก์ชัน | 20 |
จํานวนอาร์กิวเมนต์ของฟังก์ชันสูงสุด | 7 |
จำนวนการเชื่อมโยงตัวแปร let สูงสุดต่อฟังก์ชัน |
10 |
จํานวนการเรียกฟังก์ชันแบบวนซ้ำหรือแบบวนสูงสุด | 0 (not permitted) |
จำนวนนิพจน์สูงสุดที่ประเมินต่อคำขอ | 1,000 ราย |
ขนาดสูงสุดของชุดกฎ | ชุดกฎต้องเป็นไปตามขีดจํากัดขนาด 2 ข้อต่อไปนี้
|
Cloud Storage
โครงสร้างพื้นฐาน
Firebase Security Rules ใน Cloud Firestore และ Cloud Storage ใช้โครงสร้างและไวยากรณ์ต่อไปนี้
service <<name>> {
// Match the resource path.
match <<path>> {
// Allow the request if the following conditions are true.
allow <<methods>> : if <<condition>>
}
}
แนวคิดสําคัญต่อไปนี้เป็นแนวคิดที่คุณควรเข้าใจเมื่อสร้างกฎ
- คําขอ: เมธอดที่เรียกใช้ในคำสั่ง
allow
นี่เป็นเมธอดที่คุณอนุญาตให้ทํางาน วิธีการมาตรฐาน ได้แก่get
,list
,create
,update
และdelete
เมธอดที่สะดวกread
และwrite
ช่วยเปิดใช้สิทธิ์การอ่านและเขียนแบบกว้างในฐานข้อมูลหรือเส้นทางพื้นที่เก็บข้อมูลที่ระบุ - เส้นทาง: ฐานข้อมูลหรือตำแหน่งที่จัดเก็บ ซึ่งแสดงเป็นเส้นทาง URI
- กฎ: คำสั่ง
allow
ซึ่งมีเงื่อนไขที่อนุญาตคำขอหากประเมินค่าเป็น "จริง"
เส้นทางที่ตรงกัน
Cloud Storage Security Rules match
เส้นทางไฟล์ที่ใช้เข้าถึงไฟล์ใน
Cloud Storage กฎอาจเป็นmatch
เส้นทางที่ตรงกันทุกประการหรือเส้นทางไวลด์การ์ด และกฎยังซ้อนกันได้อีกด้วย หากไม่มีกฎการจับคู่ที่อนุญาตเมธอดคำขอ หรือเงื่อนไขให้ค่าเป็น false
ระบบจะปฏิเสธคําขอ
เหมือนกันทุกประการ
// Exact match for "images/profilePhoto.png" match /images/profilePhoto.png { allow write: if <condition>; } // Exact match for "images/croppedProfilePhoto.png" match /images/croppedProfilePhoto.png { allow write: if <other_condition>; }
การจับคู่ที่ซ้อนกัน
// Partial match for files that start with "images" match /images { // Exact match for "images/profilePhoto.png" match /profilePhoto.png { allow write: if <condition>; } // Exact match for "images/croppedProfilePhoto.png" match /croppedProfilePhoto.png { allow write: if <other_condition>; } }
การจับคู่ไวลด์การ์ด
นอกจากนี้ คุณยังใช้กฎเพื่อmatch
รูปแบบโดยใช้ไวลด์การ์ดได้ด้วย ไวลด์การ์ดคือตัวแปรที่มีชื่อซึ่งแสดงสตริงเดียว เช่น profilePhoto.png
หรือกลุ่มเส้นทางหลายกลุ่ม เช่น images/profilePhoto.png
ไวลด์การ์ดสร้างขึ้นโดยการใส่วงเล็บปีกการอบชื่อไวลด์การ์ด เช่น
{string}
คุณสามารถประกาศไวลด์การ์ดหลายกลุ่มได้โดยเพิ่ม =**
ลงในชื่อไวลด์การ์ด เช่น {path=**}
// Partial match for files that start with "images" match /images { // Exact match for "images/*" // e.g. images/profilePhoto.png is matched match /{imageId} { // This rule only matches a single path segment (*) // imageId is a string that contains the specific segment matched allow read: if <condition>; } // Exact match for "images/**" // e.g. images/users/user:12345/profilePhoto.png is matched // images/profilePhoto.png is also matched! match /{allImages=**} { // This rule matches one or more path segments (**) // allImages is a path that contains all segments matched allow read: if <other_condition>; } }
หากกฎหลายข้อตรงกับไฟล์ ผลลัพธ์ที่ได้คือ OR
ของผลการประเมินกฎทั้งหมด กล่าวคือ หากกฎใดก็ตามที่ไฟล์ตรงกันประเมินเป็น true
ผลลัพธ์ที่ได้คือ true
ในกฎข้างต้น ไฟล์ "images/profilePhoto.png" จะอ่านได้หาก condition
หรือ other_condition
ประเมินเป็น "จริง" ส่วนไฟล์ "images/users/user:12345/profilePhoto.png" จะขึ้นอยู่กับผลลัพธ์ของ other_condition
เท่านั้น
คุณสามารถอ้างอิงตัวแปรไวลด์การ์ดได้จากภายในmatch
การให้สิทธิ์ชื่อไฟล์หรือเส้นทาง ดังนี้
// Another way to restrict the name of a file match /images/{imageId} { allow read: if imageId == "profilePhoto.png"; }
Cloud Storage Security Rules จะไม่ทํางานแบบซ้อนทับ และระบบจะประเมินกฎก็ต่อเมื่อเส้นทางคําขอตรงกับเส้นทางที่ระบุกฎเท่านั้น
ขอรับการประเมิน
ระบบจะประเมินการอัปโหลด การดาวน์โหลด การเปลี่ยนแปลงข้อมูลเมตา และการลบโดยใช้ request
ที่ส่งไปยัง Cloud Storage ตัวแปร request
มีเส้นทางไฟล์ที่ดำเนินการตามคำขอ เวลาที่ได้รับคำขอ และค่า resource
ใหม่หากคำขอเป็นการเขียน รวมถึงส่วนหัว HTTP และสถานะการตรวจสอบสิทธิ์ด้วย
ออบเจ็กต์ request
ยังมีรหัสที่ไม่ซ้ำของผู้ใช้และเพย์โหลด Firebase Authentication อยู่ในออบเจ็กต์ request.auth
ด้วย ซึ่งจะอธิบายเพิ่มเติมในส่วนการตรวจสอบสิทธิ์ของเอกสาร
รายการพร็อพเพอร์ตี้ทั้งหมดในแอบเจ็กต์ request
มีดังนี้
พร็อพเพอร์ตี้ | ประเภท | คำอธิบาย |
---|---|---|
auth |
map<string, string> | เมื่อผู้ใช้เข้าสู่ระบบ ให้ระบุ uid ซึ่งเป็นรหัสที่ไม่ซ้ำของผู้ใช้ และ token ซึ่งเป็นการแมปการอ้างสิทธิ์ JWT Firebase Authentication มิเช่นนั้นจะเป็น null |
params |
map<string, string> | แผนที่มีพารามิเตอร์การค้นหาของคําขอ |
path |
เส้นทาง | path ที่แสดงเส้นทางที่ดำเนินการตามคำขอ |
resource |
map<string, string> | ค่าทรัพยากรใหม่ที่มีอยู่ในคําขอ write เท่านั้น
|
time |
การประทับเวลา | การประทับเวลาที่แสดงเวลาเซิร์ฟเวอร์ที่ประเมินคําขอ |
การประเมินทรัพยากร
เมื่อประเมินกฎ คุณอาจต้องประเมินข้อมูลเมตาของไฟล์ที่อัปโหลด ดาวน์โหลด แก้ไข หรือลบด้วย ซึ่งจะช่วยให้คุณสร้างกฎที่ซับซ้อนและมีประสิทธิภาพได้ เช่น อนุญาตให้อัปโหลดเฉพาะไฟล์ที่มีประเภทเนื้อหาบางอย่าง หรือลบเฉพาะไฟล์ที่มีขนาดใหญ่กว่าขนาดที่กำหนด
Firebase Security Rules สำหรับ Cloud Storage ให้ข้อมูลเมตาของไฟล์ในออบเจ็กต์ resource
ซึ่งมีคู่คีย์/ค่าของข้อมูลเมตาที่แสดงในออบเจ็กต์ Cloud Storage คุณสามารถตรวจสอบพร็อพเพอร์ตี้เหล่านี้ในคำขอ read
หรือ write
เพื่อให้มั่นใจว่าข้อมูลมีความสมบูรณ์
ในคำขอ write
(เช่น การอัปโหลด การอัปเดตข้อมูลเมตา และการลบ) นอกจากออบเจ็กต์ resource
ซึ่งมีข้อมูลเมตาของไฟล์สำหรับไฟล์ที่มีอยู่ในเส้นทางคำขอแล้ว คุณยังสามารถใช้ออบเจ็กต์ request.resource
ซึ่งมีข้อมูลเมตาของไฟล์ชุดย่อยที่จะเขียนได้หากระบบอนุญาตให้เขียน คุณสามารถใช้ 2 ค่านี้เพื่อรักษาความสมบูรณ์ของข้อมูลหรือบังคับใช้ข้อจำกัดของแอปพลิเคชัน เช่น ประเภทหรือขนาดไฟล์
รายการพร็อพเพอร์ตี้ทั้งหมดในแอบเจ็กต์ resource
มีดังนี้
พร็อพเพอร์ตี้ | ประเภท | คำอธิบาย |
---|---|---|
name |
สตริง | ชื่อเต็มของออบเจ็กต์ |
bucket |
สตริง | ชื่อของที่เก็บข้อมูลที่ออบเจ็กต์นี้อยู่ |
generation |
int | Google Cloud Storage รุ่นออบเจ็กต์ของออบเจ็กต์นี้ |
metageneration |
int | Google Cloud Storage การสร้างข้อมูลเมตาของออบเจ็กต์ของออบเจ็กต์นี้ |
size |
int | ขนาดของออบเจ็กต์ในหน่วยไบต์ |
timeCreated |
การประทับเวลา | การประทับเวลาที่แสดงเวลาที่สร้างออบเจ็กต์ |
updated |
การประทับเวลา | การประทับเวลาที่แสดงเวลาที่อัปเดตออบเจ็กต์ครั้งล่าสุด |
md5Hash |
สตริง | แฮช MD5 ของออบเจ็กต์ |
crc32c |
สตริง | แฮช CRC32c ของออบเจ็กต์ |
etag |
สตริง | ETag ที่เชื่อมโยงกับออบเจ็กต์นี้ |
contentDisposition |
สตริง | การจัดการเนื้อหาที่เชื่อมโยงกับออบเจ็กต์นี้ |
contentEncoding |
สตริง | การเข้ารหัสเนื้อหาที่เชื่อมโยงกับออบเจ็กต์นี้ |
contentLanguage |
สตริง | ภาษาของเนื้อหาที่เชื่อมโยงกับออบเจ็กต์นี้ |
contentType |
สตริง | ประเภทเนื้อหาที่เชื่อมโยงกับออบเจ็กต์นี้ |
metadata |
map<string, string> | คู่คีย์/ค่าของข้อมูลเมตาที่กำหนดเองเพิ่มเติมซึ่งนักพัฒนาแอประบุ |
request.resource
มีองค์ประกอบเหล่านี้ทั้งหมด ยกเว้น generation
, metageneration
, etag
, timeCreated
และ updated
ขีดจํากัดของกฎความปลอดภัย
โปรดคำนึงถึงขีดจำกัดต่อไปนี้เมื่อใช้กฎความปลอดภัย
ขีดจำกัด | รายละเอียด |
---|---|
จำนวนการเรียก firestore.exists() และ firestore.get() สูงสุดต่อคำขอ |
2 สำหรับคำขอเอกสารรายการเดียวและคำขอการค้นหา หากเกินขีดจํากัดนี้ ระบบจะแสดงข้อผิดพลาด "ถูกปฏิเสธสิทธิ์" ระบบอาจแคชการเรียกใช้การเข้าถึงเอกสารเดียวกันไว้ และการเรียกใช้ที่แคชไว้จะไม่นับรวมในขีดจำกัด |
ตัวอย่างแบบเต็ม
เมื่อนำทั้งหมดมารวมกัน คุณสามารถสร้างตัวอย่างกฎทั้งหมดสำหรับโซลูชันพื้นที่เก็บข้อมูลรูปภาพได้ดังนี้
service firebase.storage { match /b/{bucket}/o { match /images { // Cascade read to any image type at any path match /{allImages=**} { allow read; } // Allow write files to the path "images/*", subject to the constraints: // 1) File is less than 5MB // 2) Content type is an image // 3) Uploaded content type matches existing content type // 4) File name (stored in imageId wildcard variable) is less than 32 characters match /{imageId} { allow write: if request.resource.size < 5 * 1024 * 1024 && request.resource.contentType.matches('image/.*') && request.resource.contentType == resource.contentType && imageId.size() < 32 } } } }
Realtime Database
โครงสร้างพื้นฐาน
ใน Realtime Database Firebase Security Rules ประกอบด้วยนิพจน์ที่คล้ายกับ JavaScript ซึ่งอยู่ในเอกสาร JSON
โดยจะใช้ไวยากรณ์ต่อไปนี้
{
"rules": {
"<<path>>": {
// Allow the request if the condition for each method is true.
".read": <<condition>>,
".write": <<condition>>,
".validate": <<condition>>
}
}
}
กฎนี้มีองค์ประกอบพื้นฐาน 3 อย่าง ได้แก่
- เส้นทาง: ตำแหน่งฐานข้อมูล ซึ่งจะแสดงโครงสร้าง JSON ของฐานข้อมูล
- คำขอ: วิธีการที่กฎใช้เพื่อให้สิทธิ์เข้าถึง กฎ
read
และwrite
ให้สิทธิ์เข้าถึงแบบอ่านและเขียนอย่างกว้างขวาง ส่วนกฎvalidate
จะทำหน้าที่เป็นการตรวจสอบรองเพื่อให้สิทธิ์เข้าถึงตามข้อมูลที่เข้ามาหรือที่มีอยู่ - เงื่อนไข: เงื่อนไขที่อนุญาตคำขอหากประเมินค่าเป็นจริง
วิธีใช้กฎกับเส้นทาง
ใน Realtime Database Rules จะมีผลแบบเป็นกลุ่ม ซึ่งหมายความว่ากฎในโหนดหลักระดับที่สูงขึ้นจะลบล้างกฎในโหนดย่อยที่ละเอียดยิ่งขึ้น และกฎในโหนดที่ลึกกว่านั้นจะไม่สามารถให้สิทธิ์เข้าถึงเส้นทางหลักได้ คุณไม่สามารถปรับแต่งหรือเพิกถอนสิทธิ์เข้าถึงที่เส้นทางที่ลึกขึ้นในโครงสร้างฐานข้อมูลได้หากได้ให้สิทธิ์เข้าถึงแก่เส้นทางหลักรายการใดรายการหนึ่งแล้ว
โปรดพิจารณากฎต่อไปนี้
{ "rules": { "foo": { // allows read to /foo/* ".read": "data.child('baz').val() === true", "bar": { // ignored, since read was allowed already ".read": false } } } }
โครงสร้างความปลอดภัยนี้อนุญาตให้อ่าน /bar/
ทุกครั้งที่
/foo/
มี baz
ย่อยที่มีค่า true
กฎ ".read": false
ในส่วน /foo/bar/
จะไม่มีผลที่นี่ เนื่องจากเส้นทางย่อยไม่สามารถเพิกถอนสิทธิ์เข้าถึงได้
แม้ว่าอาจดูไม่ตรงไปตรงมาในทันที แต่นี่เป็นส่วนสําคัญของภาษากฎและช่วยให้ใช้สิทธิ์เข้าถึงที่ซับซ้อนมากได้โดยไม่ต้องทําอะไรมาก ซึ่งจะเป็นประโยชน์อย่างยิ่งสำหรับการรักษาความปลอดภัยตามผู้ใช้
อย่างไรก็ตาม กฎ .validate
จะไม่ทํางานแบบซ้อนทับ กฎการตรวจสอบทั้งหมดต้องเป็นไปตามข้อกำหนดในทุกระดับของลําดับชั้นจึงจะอนุญาตให้เขียนได้
นอกจากนี้ เนื่องจากกฎจะไม่มีผลกับเส้นทางหลัก การดำเนินการอ่านหรือเขียนจึงล้มเหลวหากไม่มีกฎในตำแหน่งที่ขอหรือในตำแหน่งหลักที่ให้สิทธิ์เข้าถึง แม้ว่าจะเข้าถึงเส้นทางย่อยที่ได้รับผลกระทบทั้งหมดได้ แต่การอ่านที่ตำแหน่งหลักจะดำเนินการไม่สำเร็จโดยสิ้นเชิง ลองดูโครงสร้างนี้
{ "rules": { "records": { "rec1": { ".read": true }, "rec2": { ".read": false } } } }
หากไม่เข้าใจว่าระบบจะประเมินกฎทีละรายการ คุณอาจคิดว่าการดึงข้อมูลเส้นทาง /records/
จะแสดงผล rec1
แต่ไม่ใช่ rec2
แต่ผลลัพธ์จริงคือข้อผิดพลาด
JavaScript
var db = firebase.database(); db.ref("records").once("value", function(snap) { // success method is not called }, function(err) { // error callback triggered with PERMISSION_DENIED });
Objective-C
FIRDatabaseReference *ref = [[FIRDatabase database] reference]; [[_ref child:@"records"] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) { // success block is not called } withCancelBlock:^(NSError * _Nonnull error) { // cancel block triggered with PERMISSION_DENIED }];
Swift
var ref = FIRDatabase.database().reference() ref.child("records").observeSingleEventOfType(.Value, withBlock: { snapshot in // success block is not called }, withCancelBlock: { error in // cancel block triggered with PERMISSION_DENIED })
Java
FirebaseDatabase database = FirebaseDatabase.getInstance(); DatabaseReference ref = database.getReference("records"); ref.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot snapshot) { // success method is not called } @Override public void onCancelled(FirebaseError firebaseError) { // error callback triggered with PERMISSION_DENIED }); });
REST
curl https://docs-examples.firebaseio.com/rest/records/ # response returns a PERMISSION_DENIED error
เนื่องจากการดำเนินการอ่านที่ /records/
เป็นการดำเนินการแบบอะตอม และไม่มีกฎการอ่านที่ให้สิทธิ์เข้าถึงข้อมูลทั้งหมดภายใต้ /records/
ระบบจะแสดงข้อผิดพลาด PERMISSION_DENIED
หากประเมินกฎนี้ในเครื่องจำลองความปลอดภัยในคอนโซล Firebase เราจะเห็นว่าการดําเนินการอ่านถูกปฏิเสธ
Attempt to read /records with auth=Success(null) / /records No .read rule allowed the operation. Read was denied.
ระบบปฏิเสธการดำเนินการเนื่องจากไม่มีกฎการอ่านที่อนุญาตให้เข้าถึงเส้นทาง /records/
แต่โปรดทราบว่าระบบไม่ได้ประเมินกฎสำหรับ rec1
เนื่องจากไม่ได้อยู่ในเส้นทางที่เราขอ หากต้องการดึงข้อมูล rec1
เราจะต้องเข้าถึงโดยตรง โดยทำดังนี้
JavaScript
var db = firebase.database(); db.ref("records/rec1").once("value", function(snap) { // SUCCESS! }, function(err) { // error callback is not called });
Objective-C
FIRDatabaseReference *ref = [[FIRDatabase database] reference]; [[ref child:@"records/rec1"] observeSingleEventOfType:FEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) { // SUCCESS! }];
Swift
var ref = FIRDatabase.database().reference() ref.child("records/rec1").observeSingleEventOfType(.Value, withBlock: { snapshot in // SUCCESS! })
Java
FirebaseDatabase database = FirebaseDatabase.getInstance(); DatabaseReference ref = database.getReference("records/rec1"); ref.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot snapshot) { // SUCCESS! } @Override public void onCancelled(FirebaseError firebaseError) { // error callback is not called } });
REST
curl https://docs-examples.firebaseio.com/rest/records/rec1 # SUCCESS!
ตัวแปรตำแหน่ง
Realtime Database Rules รองรับตัวแปร $location
เพื่อจับคู่กับส่วนของเส้นทาง ใช้คำนำหน้า $
หน้าส่วนเส้นทางเพื่อจับคู่กฎกับโหนดย่อยตามเส้นทาง
{
"rules": {
"rooms": {
// This rule applies to any child of /rooms/, the key for each room id
// is stored inside $room_id variable for reference
"$room_id": {
"topic": {
// The room's topic can be changed if the room id has "public" in it
".write": "$room_id.contains('public')"
}
}
}
}
}
นอกจากนี้ คุณยังใช้ $variable
ควบคู่ไปกับชื่อเส้นทางแบบคงที่ได้ด้วย
{
"rules": {
"widget": {
// a widget can have a title or color attribute
"title": { ".validate": true },
"color": { ".validate": true },
// but no other child paths are allowed
// in this case, $other means any key excluding "title" and "color"
"$other": { ".validate": false }
}
}
}