คู่มือนี้สร้างขึ้นจาก การเรียนรู้ไวยากรณ์หลักของคู่มือภาษากฎความปลอดภัย Firebase เพื่อแสดงวิธีเพิ่มเงื่อนไขให้กับกฎความปลอดภัย Firebase สำหรับ Cloud Storage
โครงสร้างหลักของกฎความปลอดภัยของ Cloud Storage คือ เงื่อนไข เงื่อนไขคือนิพจน์บูลีนที่กำหนดว่าการดำเนินการใดควรได้รับอนุญาตหรือปฏิเสธ สำหรับกฎพื้นฐาน การใช้ตัวอักษร true
และ false
ตามเงื่อนไขทำงานได้ดีอย่างสมบูรณ์ แต่กฎความปลอดภัย Firebase สำหรับภาษา Cloud Storage ช่วยให้คุณสามารถเขียนเงื่อนไขที่ซับซ้อนมากขึ้นซึ่งสามารถ:
- ตรวจสอบการรับรองความถูกต้องของผู้ใช้
- ตรวจสอบข้อมูลที่เข้ามา
การรับรองความถูกต้อง
กฎความปลอดภัยของ Firebase สำหรับ Cloud Storage ผสานรวมกับ Firebase Authentication เพื่อให้การตรวจสอบสิทธิ์ตามผู้ใช้ที่มีประสิทธิภาพกับ Cloud Storage ซึ่งช่วยให้สามารถควบคุมการเข้าถึงแบบละเอียดโดยอิงตามการอ้างสิทธิ์ของโทเค็น Firebase Authentication
เมื่อผู้ใช้ที่ได้รับการตรวจสอบสิทธิ์ดำเนินการร้องขอกับ Cloud Storage ตัวแปร request.auth
จะถูกเติมด้วย uid
ของผู้ใช้ ( request.auth.uid
) รวมถึงการอ้างสิทธิ์ของ Firebase Authentication JWT ( request.auth.token
)
นอกจากนี้ เมื่อใช้การรับรองความถูกต้องแบบกำหนดเอง การอ้างสิทธิ์เพิ่มเติมจะแสดงในช่อง request.auth.token
เมื่อผู้ใช้ที่ไม่ได้รับการรับรองความถูกต้องดำเนินการร้องขอ ตัวแปร request.auth
จะเป็น null
การใช้ข้อมูลนี้ มีวิธีทั่วไปหลายวิธีในการใช้การตรวจสอบสิทธิ์เพื่อรักษาความปลอดภัยไฟล์:
- สาธารณะ: เพิกเฉยต่อ
request.auth
- รับรองความถูกต้องส่วนตัว: ตรวจสอบว่า
request.auth
ไม่เป็นnull
- ผู้ใช้ส่วนตัว: ตรวจสอบว่า
request.auth.uid
เท่ากับเส้นทางuid
- กลุ่มส่วนตัว: ตรวจสอบการอ้างสิทธิ์ของโทเค็นที่กำหนดเองเพื่อให้ตรงกับการอ้างสิทธิ์ที่เลือก หรืออ่านข้อมูลเมตาของไฟล์เพื่อดูว่ามีฟิลด์ข้อมูลเมตาอยู่หรือไม่
สาธารณะ
กฎใดๆ ที่ไม่พิจารณาบริบท request.auth
สามารถถือเป็นกฎ public
ได้ เนื่องจากไม่พิจารณาบริบทการตรวจสอบสิทธิ์ของผู้ใช้ กฎเหล่านี้มีประโยชน์ในการแสดงข้อมูลสาธารณะ เช่น เนื้อหาเกม ไฟล์เสียง หรือเนื้อหาคงที่อื่นๆ
// Anyone to read a public image if the file is less than 100kB // Anyone can upload a public file ending in '.txt' match /public/{imageId} { allow read: if resource.size < 100 * 1024; allow write: if imageId.matches(".*\\.txt"); }
รับรองความถูกต้องส่วนตัว
ในบางกรณี คุณอาจต้องการให้ผู้ใช้ที่ได้รับการรับรองความถูกต้องของแอปพลิเคชันของคุณทุกคนสามารถดูข้อมูลได้ แต่ไม่ใช่โดยผู้ใช้ที่ไม่ได้รับการรับรองความถูกต้อง เนื่องจากตัวแปร request.auth
นั้นเป็น null
สำหรับผู้ใช้ที่ไม่ได้รับการรับรองความถูกต้องทั้งหมด สิ่งที่คุณต้องทำคือตรวจสอบว่ามีตัวแปร request.auth
อยู่เพื่อต้องการการรับรองความถูกต้อง:
// Require authentication on all internal image reads match /internal/{imageId} { allow read: if request.auth != null; }
ผู้ใช้ส่วนตัว
กรณีการใช้งานที่พบบ่อยที่สุดสำหรับ request.auth
คือการมอบสิทธิ์โดยละเอียดให้กับผู้ใช้แต่ละรายในไฟล์ของตน ตั้งแต่การอัปโหลดรูปโปรไฟล์ไปจนถึงการอ่านเอกสารส่วนตัว
เนื่องจากไฟล์ใน Cloud Storage มี "เส้นทาง" แบบเต็มไปยังไฟล์ สิ่งที่ต้องทำเพื่อให้ไฟล์ควบคุมโดยผู้ใช้จึงเป็นเพียงส่วนหนึ่งของข้อมูลระบุตัวผู้ใช้ที่ไม่ซ้ำใครในคำนำหน้าชื่อไฟล์ (เช่น uid
ของผู้ใช้) ที่สามารถตรวจสอบได้ เมื่อกฎได้รับการประเมิน:
// Only a user can upload their profile picture, but anyone can view it match /users/{userId}/profilePicture.png { allow read; allow write: if request.auth.uid == userId; }
กลุ่มส่วนตัว
กรณีการใช้งานทั่วไปอีกอย่างหนึ่งที่เท่าเทียมกันคือการอนุญาตกลุ่มบนออบเจ็กต์ เช่น การอนุญาตให้สมาชิกในทีมหลายคนทำงานร่วมกันในเอกสารที่แชร์ มีหลายวิธีในการทำเช่นนี้:
- สร้าง โทเค็นแบบกำหนดเองของ Firebase Authentication ที่มีข้อมูลเพิ่มเติมเกี่ยวกับสมาชิกกลุ่ม (เช่น รหัสกลุ่ม)
- รวมข้อมูลกลุ่ม (เช่น ID กลุ่มหรือรายการ
uid
ที่ได้รับอนุญาต) ไว้ใน ข้อมูลเมตาของไฟล์
เมื่อข้อมูลนี้ถูกจัดเก็บไว้ในโทเค็นหรือข้อมูลเมตาของไฟล์ จะสามารถอ้างอิงได้จากภายในกฎ:
// Allow reads if the group ID in your token matches the file metadata's `owner` property // Allow writes if the group ID is in the user's custom token match /files/{groupId}/{fileName} { allow read: if resource.metadata.owner == request.auth.token.groupId; allow write: if request.auth.token.groupId == groupId; }
ขอการประเมินผล
การอัปโหลด ดาวน์โหลด การเปลี่ยนแปลงข้อมูลเมตา และการลบจะได้รับการประเมินโดยใช้ request
ที่ส่งไปยัง Cloud Storage นอกเหนือจาก ID เฉพาะของผู้ใช้และเพย์โหลด Firebase Authentication ในออบเจ็กต์ request.auth
ตามที่อธิบายไว้ข้างต้น ตัวแปร request
ยังมีพาธของไฟล์ที่คำขอกำลังดำเนินการ เวลาที่ได้รับคำขอ และค่า resource
ใหม่หาก คำขอคือการเขียน
ออบเจ็กต์ 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
เพิ่มประสิทธิภาพด้วย Cloud Firestore
คุณสามารถเข้าถึงเอกสารใน Cloud Firestore เพื่อประเมินเกณฑ์การให้สิทธิ์อื่นๆ
การใช้ฟังก์ชัน firestore.get()
และ firestore.exists()
ทำให้กฎความปลอดภัยของคุณสามารถประเมินคำขอขาเข้าเทียบกับเอกสารใน Cloud Firestore ฟังก์ชัน firestore.get()
และ firestore.exists()
คาดหวังเส้นทางเอกสารที่ระบุอย่างครบถ้วน เมื่อใช้ตัวแปรเพื่อสร้างเส้นทางสำหรับ firestore.get()
และ firestore.exists()
คุณจะต้องหลีกเลี่ยงตัวแปรอย่างชัดเจนโดยใช้ไวยากรณ์ $(variable)
ในตัวอย่างด้านล่าง เราเห็นกฎที่จำกัดการเข้าถึงไฟล์เพื่ออ่านสำหรับผู้ใช้ที่เป็นสมาชิกของชมรมใดชมรมหนึ่ง
service firebase.storage { match /b/{bucket}/o { match /users/{club}/files/{fileId} { allow read: if club in firestore.get(/databases/(default)/documents/users/$(request.auth.id)).memberships } } }ในตัวอย่างถัดไป เฉพาะเพื่อนของผู้ใช้เท่านั้นที่สามารถดูรูปถ่ายของพวกเขาได้
service firebase.storage { match /b/{bucket}/o { match /users/{userId}/photos/{fileId} { allow read: if firestore.exists(/databases/(default)/documents/users/$(userId)/friends/$(request.auth.id)) } } }
เมื่อคุณสร้างและบันทึกกฎความปลอดภัยของ Cloud Storage แรกที่ใช้ฟังก์ชัน Cloud Firestore เหล่านี้ คุณจะได้รับแจ้งในคอนโซล Firebase หรือ Firebase CLI เพื่อเปิดใช้สิทธิ์ในการเชื่อมต่อผลิตภัณฑ์ทั้งสอง
คุณสามารถปิดใช้ฟีเจอร์นี้ได้โดยการลบบทบาท IAM ดังที่อธิบายไว้ใน จัดการและปรับใช้กฎความปลอดภัยของ Firebase
ตรวจสอบข้อมูล
กฎความปลอดภัย Firebase สำหรับ Cloud Storage ยังใช้สำหรับการตรวจสอบข้อมูล รวมถึงการตรวจสอบชื่อไฟล์และเส้นทาง ตลอดจนคุณสมบัติข้อมูลเมตาของไฟล์ เช่น contentType
และ size
service firebase.storage { match /b/{bucket}/o { match /images/{imageId} { // Only allow uploads of any image file that's less than 5MB allow write: if request.resource.size < 5 * 1024 * 1024 && request.resource.contentType.matches('image/.*'); } } }
ฟังก์ชั่นที่กำหนดเอง
เนื่องจากกฎการรักษาความปลอดภัยของ Firebase ของคุณมีความซับซ้อนมากขึ้น คุณอาจต้องการรวมชุดเงื่อนไขไว้ในฟังก์ชันที่คุณสามารถนำมาใช้ซ้ำได้ทั่วทั้งชุดกฎของคุณ กฎความปลอดภัยรองรับฟังก์ชันแบบกำหนดเอง ไวยากรณ์สำหรับฟังก์ชันแบบกำหนดเองนั้นคล้ายกับ JavaScript เล็กน้อย แต่ฟังก์ชันกฎความปลอดภัยของ Firebase เขียนในภาษาเฉพาะโดเมนซึ่งมีข้อจำกัดที่สำคัญบางประการ:
- ฟังก์ชันสามารถมีคำสั่ง
return
ได้เพียงคำสั่งเดียว ไม่สามารถมีตรรกะเพิ่มเติมใดๆ ได้ ตัวอย่างเช่น ไม่สามารถดำเนินการวนซ้ำหรือเรียกใช้บริการภายนอกได้ - ฟังก์ชันต่างๆ สามารถเข้าถึงฟังก์ชันและตัวแปรจากขอบเขตที่กำหนดไว้ได้โดยอัตโนมัติ ตัวอย่างเช่น ฟังก์ชันที่กำหนดภายในขอบเขต
service firebase.storage
มีสิทธิ์เข้าถึงตัวแปรresource
และสำหรับ Cloud Firestore เท่านั้น ฟังก์ชันในตัว เช่นget()
และexists()
- ฟังก์ชันอาจเรียกใช้ฟังก์ชันอื่นแต่อาจไม่เรียกซ้ำ ความลึกของสแต็กการโทรทั้งหมดถูกจำกัดไว้ที่ 10
- ในเวอร์ชัน
rules2
ฟังก์ชันสามารถกำหนดตัวแปรโดยใช้คีย์เวิร์ดlet
ฟังก์ชันสามารถมีจำนวนการเชื่อมโยง Let เท่าใดก็ได้ แต่ต้องลงท้ายด้วยคำสั่ง Return
ฟังก์ชันถูกกำหนดด้วยคีย์เวิร์ดของ function
และรับอาร์กิวเมนต์เป็นศูนย์หรือมากกว่า ตัวอย่างเช่น คุณอาจต้องการรวมเงื่อนไขสองประเภทที่ใช้ในตัวอย่างด้านบนเป็นฟังก์ชันเดียว:
service firebase.storage {
match /b/{bucket}/o {
// True if the user is signed in or the requested data is 'public'
function signedInOrPublic() {
return request.auth.uid != null || resource.data.visibility == 'public';
}
match /images/{imageId} {
allow read, write: if signedInOrPublic();
}
match /mp3s/{mp3Ids} {
allow read: if signedInOrPublic();
}
}
}
การใช้ฟังก์ชันในกฎความปลอดภัยของ Firebase ทำให้สามารถบำรุงรักษาได้มากขึ้นเมื่อกฎของคุณมีความซับซ้อนมากขึ้น
ขั้นตอนถัดไป
หลังจากการหารือเกี่ยวกับเงื่อนไขนี้ คุณจะมีความเข้าใจกฎที่ซับซ้อนมากขึ้น และพร้อมที่จะ:
เรียนรู้วิธีจัดการกับกรณีการใช้งานหลัก และเรียนรู้ขั้นตอนการทำงานสำหรับการพัฒนา การทดสอบ และการปรับใช้กฎ:
- เขียนกฎที่จัดการกับ สถานการณ์ทั่วไป
- ต่อยอดความรู้ของคุณโดยการทบทวนสถานการณ์ที่คุณต้อง สังเกตและหลีกเลี่ยงกฎที่ไม่ปลอดภัย
- ทดสอบกฎโดยใช้ โปรแกรมจำลอง Cloud Storage และไลบรารีทดสอบกฎความปลอดภัยโดยเฉพาะ
- ตรวจสอบวิธีการที่มีอยู่สำหรับ การปรับใช้กฎ