คู่มือนี้สร้างขึ้นจากคู่มือเรียนรู้ไวยากรณ์หลักของภาษาของกฎการรักษาความปลอดภัยของ Firebase เพื่อแสดงวิธีเพิ่มเงื่อนไขในกฎการรักษาความปลอดภัยของ Firebase สำหรับ Cloud Storage
องค์ประกอบที่ใช้สร้างสรรค์หลักของกฎความปลอดภัยของ Cloud Storage คือเงื่อนไข เงื่อนไขคือนิพจน์บูลีนที่กำหนดว่าควรอนุญาตหรือปฏิเสธการดำเนินการเฉพาะ สำหรับกฎพื้นฐาน การใช้ true
และ false
ลิเทอรัล
เป็นเงื่อนไขที่ใช้ได้ดี แต่กฎการรักษาความปลอดภัยของ Firebase สำหรับภาษาของ Cloud Storage มอบวิธีในการเขียนเงื่อนไขที่ซับซ้อนขึ้น ซึ่งสามารถทำสิ่งต่อไปนี้
- ตรวจสอบการตรวจสอบสิทธิ์ผู้ใช้
- ตรวจสอบข้อมูลขาเข้า
การตรวจสอบสิทธิ์
กฎการรักษาความปลอดภัยของ Firebase สำหรับ Cloud Storage จะผสานรวมกับการตรวจสอบสิทธิ์ Firebase เพื่อมอบการตรวจสอบสิทธิ์ตามผู้ใช้ที่มีประสิทธิภาพสูงไปยัง Cloud Storage ซึ่งช่วยให้ควบคุมการเข้าถึงได้อย่างละเอียดตามการอ้างสิทธิ์โทเค็นการตรวจสอบสิทธิ์ Firebase
เมื่อผู้ใช้ที่ตรวจสอบสิทธิ์แล้วส่งคำขอกับ Cloud Storage ระบบจะป้อนข้อมูลตัวแปร request.auth
ด้วย uid
(request.auth.uid
) ของผู้ใช้ รวมถึงการอ้างสิทธิ์ JWT การตรวจสอบสิทธิ์ของ Firebase (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 ที่มีข้อมูลเพิ่มเติมเกี่ยวกับสมาชิกกลุ่ม (เช่น รหัสกลุ่ม)
- ใส่ข้อมูลกลุ่ม (เช่น รหัสกลุ่มหรือรายการ
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 นอกจากรหัสที่ไม่ซ้ำกันของผู้ใช้และเพย์โหลดการตรวจสอบสิทธิ์ Firebase ในออบเจ็กต์ request.auth
ตามที่อธิบายไว้ข้างต้นแล้ว ตัวแปร request
ยังมีเส้นทางไฟล์ที่กำลังดำเนินการ เวลาที่ได้รับคำขอ และค่า resource
ใหม่หากคำขอนั้นเป็นการเขียน
นอกจากนี้ ออบเจ็กต์ request
ยังมีรหัสที่ไม่ซ้ำกันของผู้ใช้และเพย์โหลดการตรวจสอบสิทธิ์ Firebase ในออบเจ็กต์ request.auth
ซึ่งจะอธิบายเพิ่มเติมในส่วน User-Based Security ของเอกสาร
รายการที่พักทั้งหมดในออบเจ็กต์ request
แสดงอยู่ด้านล่าง
พร็อพเพอร์ตี้ | ประเภท | คำอธิบาย |
---|---|---|
auth |
แมป<สตริง, สตริง> | เมื่อผู้ใช้เข้าสู่ระบบ ให้ระบุ uid , รหัสที่ไม่ซ้ำกันของผู้ใช้ และ token ซึ่งเป็นแมปการอ้างสิทธิ์ JWT การตรวจสอบสิทธิ์ของ Firebase หากไม่ระบุ ค่าจะเป็น null |
params |
แมป<สตริง, สตริง> | แผนที่ที่มีพารามิเตอร์การค้นหาของคำขอ |
path |
เส้นทาง | path ที่แสดงเส้นทางที่กำลังดำเนินการคำขอ |
resource |
แมป<สตริง, สตริง> | ค่าทรัพยากรใหม่ แสดงเฉพาะในคำขอ write เท่านั้น
|
time |
การประทับเวลา | การประทับเวลาที่แสดงถึงเวลาของเซิร์ฟเวอร์ที่มีการประเมินคำขอ |
การประเมินทรัพยากร
เมื่อประเมินกฎ คุณอาจต้องประเมินข้อมูลเมตาของไฟล์ที่อัปโหลด ดาวน์โหลด แก้ไข หรือลบ วิธีนี้ช่วยให้คุณสร้างกฎที่ซับซ้อนและมีประสิทธิภาพสูง เช่น อนุญาตให้อัปโหลดเฉพาะไฟล์ที่มีเนื้อหาบางประเภท หรือจะลบเฉพาะไฟล์ที่มีขนาดใหญ่กว่าขนาดที่กำหนด
กฎการรักษาความปลอดภัยของ Firebase สำหรับ Cloud Storage จะมีข้อมูลเมตาของไฟล์ในออบเจ็กต์ resource
ซึ่งมีคู่คีย์/ค่าของข้อมูลเมตาที่แสดงในออบเจ็กต์ Cloud Storage คุณสามารถตรวจสอบพร็อพเพอร์ตี้เหล่านี้ได้ในคำขอ read
หรือ write
เพื่อตรวจสอบความสมบูรณ์ของข้อมูล
ในคำขอ write
(เช่น การอัปโหลด การอัปเดตข้อมูลเมตา และลบ) นอกเหนือจากออบเจ็กต์ resource
ซึ่งมีข้อมูลเมตาของไฟล์สำหรับไฟล์ที่มีอยู่ในเส้นทางคำขออยู่แล้ว คุณยังใช้ออบเจ็กต์ request.resource
ซึ่งมีชุดย่อยของข้อมูลเมตาของไฟล์ที่จะเขียนได้ หากอนุญาตให้เขียนได้ คุณอาจใช้ค่า 2 ค่านี้เพื่อตรวจสอบความสมบูรณ์ของข้อมูลหรือบังคับใช้ข้อจำกัดของแอปพลิเคชัน เช่น ประเภทไฟล์หรือขนาดไฟล์
รายการที่พักทั้งหมดในออบเจ็กต์ resource
แสดงอยู่ด้านล่าง
พร็อพเพอร์ตี้ | ประเภท | คำอธิบาย |
---|---|---|
name |
string | ชื่อเต็มของออบเจ็กต์ |
bucket |
string | ชื่อของที่เก็บข้อมูลที่มีออบเจ็กต์นี้ |
generation |
int | การสร้างออบเจ็กต์ Google Cloud Storage ของออบเจ็กต์นี้ |
metageneration |
int | เมตาการสร้างออบเจ็กต์ Google Cloud Storage ของออบเจ็กต์นี้ |
size |
int | ขนาดของออบเจ็กต์ในหน่วยไบต์ |
timeCreated |
การประทับเวลา | การประทับเวลาที่แสดงถึงเวลาที่สร้างออบเจ็กต์ |
updated |
การประทับเวลา | การประทับเวลาที่แสดงถึงเวลาที่อัปเดตออบเจ็กต์ครั้งล่าสุด |
md5Hash |
string | แฮช MD5 ของออบเจ็กต์ |
crc32c |
string | แฮช crc32c ของออบเจ็กต์ |
etag |
string | eTag ที่เชื่อมโยงกับออบเจ็กต์นี้ |
contentDisposition |
string | การจัดการเนื้อหาที่เชื่อมโยงกับออบเจ็กต์นี้ |
contentEncoding |
string | การเข้ารหัสเนื้อหาที่เชื่อมโยงกับออบเจ็กต์นี้ |
contentLanguage |
string | ภาษาของเนื้อหาที่เชื่อมโยงกับออบเจ็กต์นี้ |
contentType |
string | ประเภทเนื้อหาที่เชื่อมโยงกับออบเจ็กต์นี้ |
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 กี่รายการก็ได้ แต่ต้องลงท้ายด้วยคำสั่งส่งกลับ
ระบบจะกำหนดฟังก์ชันด้วยคีย์เวิร์ด function
และไม่มีอาร์กิวเมนต์ใดๆ เช่น คุณอาจต้องการรวมเงื่อนไข 2 ประเภทที่ใช้ในตัวอย่างด้านบนเข้าเป็นฟังก์ชันเดียว
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 และไลบรารีทดสอบกฎการรักษาความปลอดภัยโดยเฉพาะ
- ดูวิธีการสำหรับการทำให้กฎใช้งานได้