ความปลอดภัยอาจเป็นหนึ่งในปริศนาการพัฒนาแอปที่ซับซ้อนที่สุด ในแอปพลิเคชันส่วนใหญ่ นักพัฒนาจะต้องสร้างและใช้งานเซิร์ฟเวอร์ที่จัดการการรับรองความถูกต้อง (ผู้ใช้คือใคร) และการอนุญาต (สิ่งที่ผู้ใช้สามารถทำได้)
กฎความปลอดภัยของ Firebase จะลบเลเยอร์กลาง (เซิร์ฟเวอร์) และอนุญาตให้คุณระบุสิทธิ์ตามเส้นทางสำหรับไคลเอนต์ที่เชื่อมต่อกับข้อมูลของคุณโดยตรง ใช้คู่มือนี้เพื่อเรียนรู้เพิ่มเติมเกี่ยวกับวิธีการนำกฎไปใช้กับคำขอที่เข้ามา
เลือกผลิตภัณฑ์เพื่อเรียนรู้เพิ่มเติมเกี่ยวกับกฎของผลิตภัณฑ์
คลาวด์ไฟร์สโตร์
โครงสร้างพื้นฐาน
กฎความปลอดภัยของ 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
อย่างไรก็ตาม โปรดทราบว่าลักษณะการทำงานของไวด์การ์ดแบบเรียกซ้ำจะขึ้นอยู่กับเวอร์ชันของกฎ
เวอร์ชัน 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 |
ขนาดสูงสุดของชุดกฎ | ชุดกฎต้องเป็นไปตามขีดจำกัดขนาด 2 ประการ:
|
การจัดเก็บเมฆ
โครงสร้างพื้นฐาน
กฎความปลอดภัยของ 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
ไวด์การ์ดถูกสร้างขึ้นโดยการเพิ่มเครื่องหมายปีกการอบๆ ชื่อไวด์การ์ด เช่น {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 จะไม่เรียงซ้อน และกฎจะได้รับการประเมินเมื่อเส้นทางคำขอตรงกับเส้นทางที่มีกฎที่ระบุเท่านั้น
ขอประเมินผล
การอัปโหลด ดาวน์โหลด การเปลี่ยนแปลงข้อมูลเมตา และการลบจะได้รับการประเมินโดยใช้ request
ที่ส่งไปยัง Cloud Storage ตัวแปร request
ประกอบด้วยพาธของไฟล์ที่คำขอกำลังดำเนินการ เวลาที่ได้รับคำขอ และค่า resource
ใหม่หากคำขอเป็นการเขียน รวมถึงส่วนหัว HTTP และสถานะการตรวจสอบสิทธิ์ด้วย
ออบเจ็กต์ request
ยังประกอบด้วย ID เฉพาะของผู้ใช้และเพย์โหลด Firebase Authentication ในออบเจ็ก 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 | ภายใน | การสร้างออบเจ็กต์ Google Cloud Storage ของออบเจ็กต์นี้ |
metageneration | ภายใน | การสร้างเมตาออบเจ็กต์ Google Cloud Storage ของออบเจ็กต์นี้ |
size | ภายใน | ขนาดของวัตถุเป็นไบต์ |
timeCreated | การประทับเวลา | การประทับเวลาที่แสดงเวลาที่สร้างออบเจ็กต์ |
updated | การประทับเวลา | การประทับเวลาที่แสดงเวลาที่ออบเจ็กต์ได้รับการอัปเดตครั้งล่าสุด |
md5Hash | เชือก | แฮช MD5 ของวัตถุ |
crc32c | เชือก | แฮช crc32c ของวัตถุ |
etag | เชือก | etag ที่เกี่ยวข้องกับวัตถุนี้ |
contentDisposition | เชือก | การจัดการเนื้อหาที่เกี่ยวข้องกับวัตถุนี้ |
contentEncoding | เชือก | การเข้ารหัสเนื้อหาที่เกี่ยวข้องกับวัตถุนี้ |
contentLanguage | เชือก | ภาษาของเนื้อหาที่เกี่ยวข้องกับวัตถุนี้ |
contentType | เชือก | ประเภทเนื้อหาที่เกี่ยวข้องกับวัตถุนี้ |
metadata | แผนที่ <สตริง, สตริง> | คู่คีย์/ค่าของข้อมูลเมตาที่กำหนดเองเพิ่มเติมที่นักพัฒนาระบุ |
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 } } } }
ฐานข้อมูลเรียลไทม์
โครงสร้างพื้นฐาน
ในฐานข้อมูลเรียลไทม์ กฎความปลอดภัยของ 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/
เมื่อใดก็ตามที่ /foo/
มี child baz
ที่มีค่า true
".read": false
ภายใต้ /foo/bar/
ไม่มีผลกระทบที่นี่ เนื่องจากการเข้าถึงไม่สามารถเพิกถอนได้โดยเส้นทางลูก
แม้ว่าอาจดูไม่เป็นธรรมชาติในทันที แต่นี่เป็นส่วนที่มีประสิทธิภาพของภาษากฎ และช่วยให้สิทธิ์การเข้าถึงที่ซับซ้อนมากสามารถนำไปใช้ได้โดยใช้ความพยายามเพียงเล็กน้อย สิ่งนี้มีประโยชน์อย่างยิ่งสำหรับ การรักษาความปลอดภัยตามผู้ใช้
อย่างไรก็ตาม กฎ .validate
จะไม่เรียงซ้อน กฎการตรวจสอบทั้งหมดต้องเป็นไปตามลำดับชั้นทุกระดับจึงจะอนุญาตให้เขียนได้
นอกจากนี้ เนื่องจากกฎไม่ได้ใช้กลับกับเส้นทางหลัก การดำเนินการอ่านหรือเขียนจึงล้มเหลวหากไม่มีกฎในตำแหน่งที่ร้องขอหรือที่ตำแหน่งหลักที่ให้สิทธิ์การเข้าถึง แม้ว่าทุกเส้นทางลูกที่ได้รับผลกระทบจะสามารถเข้าถึงได้ แต่การอ่านที่ตำแหน่งหลักจะล้มเหลวโดยสิ้นเชิง พิจารณาโครงสร้างนี้:
{ "rules": { "records": { "rec1": { ".read": true }, "rec2": { ".read": false } } } }
หากไม่เข้าใจว่ากฎได้รับการประเมินแบบอะตอมมิก อาจดูเหมือนว่าการดึงข้อมูลเส้นทาง /records/
จะส่งกลับ rec1
แต่ไม่ใช่ rec2
อย่างไรก็ตาม ผลลัพธ์ที่แท้จริงคือข้อผิดพลาด:
จาวาสคริปต์
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 }];
สวิฟท์
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 })
ชวา
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
เราจะต้องเข้าถึงโดยตรง:
จาวาสคริปต์
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! }];
สวิฟท์
var ref = FIRDatabase.database().reference() ref.child("records/rec1").observeSingleEventOfType(.Value, withBlock: { snapshot in // SUCCESS! })
ชวา
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 }
}
}
}