ความปลอดภัยอาจเป็นหนึ่งในส่วนที่ซับซ้อนที่สุดของปริศนาการพัฒนาแอป ในแอปพลิเคชันส่วนใหญ่ นักพัฒนาต้องสร้างและเรียกใช้เซิร์ฟเวอร์ที่จัดการการรับรองความถูกต้อง (ใครคือผู้ใช้) และการอนุญาต (สิ่งที่ผู้ใช้สามารถทำได้)
กฎความปลอดภัยของ Firebase ลบเลเยอร์กลาง (เซิร์ฟเวอร์) และอนุญาตให้คุณระบุสิทธิ์ตามเส้นทางสำหรับไคลเอ็นต์ที่เชื่อมต่อกับข้อมูลของคุณโดยตรง ใช้คู่มือนี้เพื่อเรียนรู้เพิ่มเติมเกี่ยวกับวิธีการใช้กฎกับคำขอที่เข้ามา
เลือกผลิตภัณฑ์เพื่อเรียนรู้เพิ่มเติมเกี่ยวกับกฎของผลิตภัณฑ์
Cloud Firestore
โครงสร้างพื้นฐาน
กฎความปลอดภัยของ Firebase ใน 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
อย่างไรก็ตาม โปรดทราบว่าลักษณะการทำงานของ wildcard แบบเรียกซ้ำนั้นขึ้นอยู่กับเวอร์ชันของกฎ
เวอร์ชั่น 1
กฎความปลอดภัยใช้เวอร์ชัน 1 โดยค่าเริ่มต้น ในเวอร์ชัน 1 อักขระตัวแทนแบบเรียกซ้ำจะจับคู่รายการพาธตั้งแต่หนึ่งรายการขึ้นไป ไม่ตรงกับเส้นทางที่ว่างเปล่า ดังนั้น match /cities/{city}/{document=**}
จะจับคู่เอกสารในคอลเล็กชันย่อยแต่ไม่จับคู่ในคอลเล็กชัน cities
ในขณะที่ match /cities/{document=**}
จะจับคู่เอกสารทั้งสองใน คอลเลกชัน cities
และคอลเลกชันย่อย
สัญลักษณ์แทนแบบเรียกซ้ำต้องอยู่ท้ายคำสั่งการแข่งขัน
รุ่น2
ในกฎความปลอดภัยเวอร์ชัน 2 ไวด์การ์ดแบบเรียกซ้ำจะจับคู่รายการพาธศูนย์หรือมากกว่า 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>;
}
}
}
คุณสามารถมีสัญลักษณ์แทนแบบเรียกซ้ำได้มากสุดหนึ่งรายการต่อคำสั่งการจับคู่ แต่ในเวอร์ชัน 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
มากกว่าหนึ่งคำสั่ง ในกรณีที่นิพจน์ 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
จะได้รับอนุญาต เนื่องจากกฎข้อที่สองเป็น true
เสมอ แม้ว่ากฎข้อแรกจะเป็น false
เสมอ
ขีดจำกัดกฎความปลอดภัย
ขณะที่คุณทำงานกับกฎความปลอดภัย ให้สังเกตข้อจำกัดต่อไปนี้:
ขีดจำกัด | รายละเอียด |
---|---|
จำนวนสูงสุดของการโทรที่ exists() , get() และ getAfter() การโทรต่อคำขอ |
เกินขีดจำกัดอย่างใดอย่างหนึ่งส่งผลให้เกิดข้อผิดพลาดในการปฏิเสธการอนุญาต การโทรเข้าถึงเอกสารบางรายการอาจถูกแคชไว้ และการเรียกใช้ที่แคชจะไม่นับรวมในขีดจำกัด |
ความลึกคำสั่ง match ซ้อนกันสูงสุด | 10 |
ความยาวเส้นทางสูงสุด ในส่วนของเส้นทาง อนุญาตภายในชุดคำสั่ง match ที่ซ้อนกัน | 100 |
จำนวนตัวแปรการดักจับเส้นทางสูงสุดที่อนุญาตภายในชุดคำสั่ง match ที่ซ้อนกัน | 20 |
ความลึกของการเรียกฟังก์ชันสูงสุด | 20 |
จำนวนอาร์กิวเมนต์ฟังก์ชันสูงสุด | 7 |
จำนวนสูงสุดของการโยงตัวแปร let ต่อฟังก์ชัน | 10 |
จำนวนสูงสุดของการเรียกฟังก์ชันแบบเรียกซ้ำหรือแบบวนซ้ำ | 0 (ไม่อนุญาต) |
จำนวนนิพจน์สูงสุดที่ประเมินต่อคำขอ | 1,000 |
ขนาดสูงสุดของชุดกฎ | ชุดกฎต้องเป็นไปตามขีดจำกัดสองขนาด:
|
การจัดเก็บเมฆ
โครงสร้างพื้นฐาน
กฎความปลอดภัยของ Firebase ใน 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 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
wildcard ถูกสร้างขึ้นโดยการเพิ่มวงเล็บปีกการอบๆ ชื่อ wildcard เช่น {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
หรือเงื่อนไขอื่น ๆ ประเมินว่าเป็นจริง ในขณะที่ไฟล์ "images/users/user:12345/profilePhoto.png" จะขึ้นอยู่กับผลลัพธ์ของ other_condition
other_condition
.
ตัวแปรไวด์การ์ดสามารถอ้างอิงได้จากการ match
ชื่อไฟล์หรือการอนุญาตเส้นทาง:
// Another way to restrict the name of a file match /images/{imageId} { allow read: if imageId == "profilePhoto.png"; }
กฎความปลอดภัยของ Cloud Storage ไม่ต่อเรียง และกฎจะได้รับการประเมินเมื่อเส้นทางคำขอตรงกับเส้นทางที่มีกฎที่ระบุเท่านั้น
ขอการประเมิน
การอัปโหลด ดาวน์โหลด การเปลี่ยนแปลงข้อมูลเมตา และการลบจะได้รับการประเมินโดยใช้ request
ที่ส่งไปยัง Cloud Storage ตัวแปร request
ประกอบด้วยเส้นทางของไฟล์ที่ดำเนินการตามคำขอ เวลาที่รับคำขอ และค่า resource
ใหม่หากคำขอเป็นการเขียน รวมส่วนหัว HTTP และสถานะการตรวจสอบสิทธิ์ด้วย
ออบเจ็กต์ request
ยังมี ID เฉพาะของผู้ใช้และเพย์โหลดการตรวจสอบสิทธิ์ Firebase ในอ็อบเจ็กต์ request.auth
ซึ่งจะอธิบายเพิ่มเติมในส่วนการ ตรวจสอบสิทธิ์ ของเอกสาร
รายการคุณสมบัติทั้งหมดในวัตถุ request
มีอยู่ด้านล่าง:
คุณสมบัติ | พิมพ์ | คำอธิบาย |
---|---|---|
auth | แผนที่<สตริง สตริง> | เมื่อผู้ใช้เข้าสู่ระบบ ให้ระบุ uid ID เฉพาะของผู้ใช้ และ token แผนที่ของ Firebase Authentication JWT อ้างสิทธิ์ มิฉะนั้นจะเป็น null |
params | แผนที่<สตริง สตริง> | แผนที่ที่มีพารามิเตอร์การค้นหาของคำขอ |
path | เส้นทาง | path ที่แสดงเส้นทางที่ร้องขอกำลังดำเนินการอยู่ |
resource | แผนที่<สตริง สตริง> | ค่าทรัพยากรใหม่ แสดงเฉพาะในคำขอ write |
time | การประทับเวลา | การประทับเวลาที่แสดงเวลาเซิร์ฟเวอร์ที่คำขอได้รับการประเมิน |
การประเมินทรัพยากร
เมื่อประเมินกฎ คุณอาจต้องการประเมินข้อมูลเมตาของไฟล์ที่กำลังอัปโหลด ดาวน์โหลด แก้ไข หรือลบ วิธีนี้ช่วยให้คุณสร้างกฎที่ซับซ้อนและมีประสิทธิภาพซึ่งทำสิ่งต่างๆ เช่น อนุญาตให้อัปโหลดเฉพาะไฟล์ที่มีเนื้อหาบางประเภท หรือลบเฉพาะไฟล์ที่มีขนาดใหญ่กว่าขนาดที่กำหนด
กฎความปลอดภัยของ Firebase สำหรับ Cloud Storage ให้ข้อมูลเมตาของไฟล์ในออบเจ็กต์ resource
ซึ่งประกอบด้วยคู่คีย์/ค่าของข้อมูลเมตาที่แสดงในออบเจ็กต์ Cloud Storage คุณสมบัติเหล่านี้สามารถตรวจสอบได้ในคำขอ read
หรือ write
เพื่อรับรองความถูกต้องของข้อมูล
ในคำขอ write
(เช่น การอัปโหลด การอัปเดตข้อมูลเมตา และการลบ) นอกเหนือจากออบเจ็กต์ resource
ซึ่งมีข้อมูลเมตาของไฟล์สำหรับไฟล์ที่มีอยู่ในปัจจุบันที่เส้นทางคำขอ คุณยังมีความสามารถในการใช้อ็อบเจ็กต์ request.resource
ซึ่งมีชุดย่อยของข้อมูลเมตาของไฟล์ที่จะเขียนหากอนุญาตให้เขียน คุณสามารถใช้สองค่านี้เพื่อรับรองความถูกต้องของข้อมูลหรือบังคับใช้ข้อจำกัดของแอปพลิเคชัน เช่น ประเภทหรือขนาดไฟล์
รายการคุณสมบัติทั้งหมดในวัตถุ 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 | แผนที่<สตริง สตริง> | คู่คีย์/ค่าของข้อมูลเมตาที่กำหนดเองเพิ่มเติมที่นักพัฒนาระบุ |
request.resource
มีสิ่งเหล่านี้ทั้งหมด ยกเว้น generation
, metageneration
, etag
, timeCreated
และ updated
ตัวอย่างเต็ม
เมื่อนำทุกอย่างมารวมกัน คุณสามารถสร้างตัวอย่างกฎสำหรับโซลูชันการจัดเก็บรูปภาพทั้งหมดได้:
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 } } } }
ฐานข้อมูลเรียลไทม์
โครงสร้างพื้นฐาน
ในฐานข้อมูลแบบเรียลไทม์ กฎความปลอดภัยของ Firebase ประกอบด้วยนิพจน์ที่เหมือน JavaScript ที่มีอยู่ในเอกสาร JSON
พวกเขาใช้ไวยากรณ์ต่อไปนี้:
{
"rules": {
"<<path>>": {
// Allow the request if the condition for each method is true.
".read": <<condition>>,
".write": <<condition>>,
".validate": <<condition>>
}
}
}
มีองค์ประกอบพื้นฐานสามประการในกฎ:
- เส้นทาง: ตำแหน่งฐานข้อมูล สิ่งนี้สะท้อนโครงสร้าง JSON ของฐานข้อมูลของคุณ
- คำขอ: นี่คือวิธีที่กฎใช้ในการให้สิทธิ์การเข้าถึง กฎการ
read
และwrite
ให้สิทธิ์การเข้าถึงแบบอ่านและเขียนในวงกว้าง ในขณะที่กฎการvalidate
จะทำหน้าที่เป็นการยืนยันรองเพื่อให้สิทธิ์การเข้าถึงตามข้อมูลขาเข้าหรือที่มีอยู่ - เงื่อนไข: เงื่อนไขที่อนุญาตคำขอหากประเมินว่าเป็นจริง
กฎเกณฑ์ที่ใช้กับเส้นทางอย่างไร
ในฐานข้อมูลเรียลไทม์ กฎจะใช้อะตอมมิก หมายความว่ากฎที่โหนดระดับบนสุดจะแทนที่กฎที่โหนดย่อยที่ละเอียดยิ่งขึ้น และกฎที่โหนดที่ลึกกว่านั้นไม่สามารถให้สิทธิ์การเข้าถึงเส้นทางหลักได้ คุณไม่สามารถปรับแต่งหรือเพิกถอนการเข้าถึงในเส้นทางที่ลึกกว่าในโครงสร้างฐานข้อมูลของคุณได้ ถ้าคุณได้ให้สิทธิ์การเข้าถึงสำหรับพาธพาเรนต์อันใดอันหนึ่งแล้ว
พิจารณากฎต่อไปนี้:
{ "rules": { "foo": { // allows read to /foo/* ".read": "data.child('baz').val() === true", "bar": { // ignored, since read was allowed already ".read": false } } } }
โครงสร้างความปลอดภัยนี้อนุญาตให้อ่าน /bar/
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 });
วัตถุประสงค์-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 }); });
พักผ่อน
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 });
วัตถุประสงค์-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 } });
พักผ่อน
curl https://docs-examples.firebaseio.com/rest/records/rec1 # SUCCESS!
ตัวแปรตำแหน่ง
กฎฐานข้อมูลเรียลไทม์สนับสนุนตัวแปร $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 }
}
}
}