ความปลอดภัยอาจเป็นหนึ่งในปริศนาการพัฒนาแอพที่ซับซ้อนที่สุด ในแอปพลิเคชันส่วนใหญ่ นักพัฒนาจะต้องสร้างและเรียกใช้เซิร์ฟเวอร์ที่จัดการการรับรองความถูกต้อง (ผู้ใช้คือใคร) และการอนุญาต (สิ่งที่ผู้ใช้สามารถทำได้)
กฎความปลอดภัยของ 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
อย่างไรก็ตาม โปรดทราบว่าลักษณะการทำงานของสัญลักษณ์ตัวแทนแบบเรียกซ้ำนั้นขึ้นอยู่กับเวอร์ชันของกฎ
รุ่น 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
สัญลักษณ์ตัวแทนถูกสร้างขึ้นโดยการเพิ่มวงเล็บปีกการอบชื่อสัญลักษณ์ตัวแทน เช่น {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 ในออบเจ็ก request.auth
ซึ่งจะอธิบายเพิ่มเติมในส่วน การรับรองความถูกต้อง ของเอกสาร
รายการคุณสมบัติทั้งหมดในออบเจกต์ request
มีอยู่ด้านล่าง:
คุณสมบัติ | พิมพ์ | คำอธิบาย |
---|---|---|
auth | แผนที่<string, string> | เมื่อผู้ใช้เข้าสู่ระบบ ให้ระบุ uid ID เฉพาะของผู้ใช้ และ token แผนที่ของการอ้างสิทธิ์ Firebase Authentication JWT มิฉะนั้นจะเป็น null |
params | แผนที่<string, string> | แผนที่ที่มีพารามิเตอร์การค้นหาของคำขอ |
path | เส้นทาง | path ที่แสดงเส้นทางที่คำขอกำลังดำเนินการอยู่ |
resource | แผนที่<string, string> | ค่าทรัพยากรใหม่ แสดงเฉพาะในคำขอ 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 | แผนที่<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 } } } }
ฐานข้อมูลเรียลไทม์
โครงสร้างพื้นฐาน
ในฐานข้อมูลเรียลไทม์ กฎความปลอดภัยของ 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/
มี 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 }
}
}
}