ความปลอดภัยอาจเป็นหนึ่งในส่วนที่ซับซ้อนที่สุดของปริศนาการพัฒนาแอป ในแอปพลิเคชันส่วนใหญ่ นักพัฒนาแอปต้องสร้างและเรียกใช้เซิร์ฟเวอร์ที่จัดการการตรวจสอบสิทธิ์ (ผู้ใช้คือใคร) และการให้สิทธิ์ (ผู้ใช้ทำอะไรได้บ้าง)
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 สามารถชี้ไปยังเอกสารที่เฉพาะเจาะจงได้ เช่น match /cities/SF หรือใช้ไวลด์การ์ด
เพื่อชี้ไปยังเอกสารใดก็ได้ในเส้นทางที่ระบุ เช่น match /cities/{city}
ในตัวอย่างนี้ คำสั่ง match ใช้ไวยากรณ์ไวลด์การ์ด {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>;
}
}
}
ข้อความที่ตรงกันซึ่งซ้อนทับกัน
เอกสารอาจตรงกับ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.
match /cities/{document} {
allow read, write: if true;
}
}
}
ในตัวอย่างนี้ ระบบจะอนุญาตการอ่านและการเขียนทั้งหมดไปยังคอลเล็กชัน cities เนื่องจากกฎที่ 2 เป็น true เสมอ แม้ว่ากฎแรกจะเป็น false เสมอ
ไวลด์การ์ดแบบเรียกซ้ำ
หากต้องการให้กฎมีผลกับลำดับชั้นที่ลึกโดยพลการ ให้ใช้ไวยากรณ์ไวลด์การ์ดแบบเรียกซ้ำ {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 ดูการรักษาความปลอดภัยให้กับการค้นหากลุ่มคอลเล็กชัน
ขีดจำกัดของกฎความปลอดภัย
ขณะทำงานกับกฎความปลอดภัย โปรดทราบขีดจำกัดต่อไปนี้
| ขีดจำกัด | รายละเอียด |
|---|---|
จำนวนการเรียก exists(), get() และ getAfter() สูงสุดต่อคำขอ |
หากเกินขีดจำกัดใดขีดจำกัดหนึ่ง ระบบจะแสดงข้อผิดพลาด "ปฏิเสธสิทธิ์" ระบบอาจแคชการเรียกใช้การเข้าถึงเอกสารบางรายการ และการเรียกใช้ที่แคชไว้จะไม่นับรวมในโควต้า |
ความลึกสูงสุดของคำสั่ง match ที่ซ้อนกัน |
10 |
ความยาวเส้นทางสูงสุดในส่วนเส้นทางที่อนุญาตภายในชุดคำสั่ง match ที่ซ้อนกัน |
100 |
จำนวนตัวแปรการบันทึกเส้นทางสูงสุดที่อนุญาตภายในชุดคำสั่ง match ที่ซ้อนกัน
|
20 |
| ความลึกสูงสุดของการเรียกใช้ฟังก์ชัน | 20 |
| จำนวนอาร์กิวเมนต์ของฟังก์ชันสูงสุด | 7 |
จำนวนการเชื่อมโยงตัวแปร let สูงสุดต่อฟังก์ชัน |
10 |
| จำนวนการเรียกฟังก์ชันแบบเรียกซ้ำหรือแบบวนรอบสูงสุด | 0 (ไม่อนุญาต) |
| จำนวนสูงสุดของนิพจน์ที่ประเมินต่อคำขอ | 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 provide filename
หรือการให้สิทธิ์เส้นทาง
// 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 |
สตริง | แท็ก E ที่เชื่อมโยงกับออบเจ็กต์นี้ |
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 { // 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) Filename (stored in imageId wildcard variable) is less than 32 characters match /{imageId} { allow read; 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 }
}
}
}