本指南以「瞭解 Firebase 安全性規則語言的核心語法」指南為基礎,說明如何在 Cloud Storage 的 Firebase 安全性規則中新增條件。
Cloud Storage 安全性規則的主要構成要素為條件。條件是一種布林值運算式,可判定是否應允許或拒絕特定作業。如果是基本規則,使用 true
和 false
常值做為條件的最佳方式。但 Cloud Storage 語言適用的 Firebase 安全性規則
可讓您編寫更複雜的條件,進而:
- 檢查使用者驗證
- 驗證傳入的資料
驗證機制
Cloud Storage 的 Firebase 安全性規則可與 Firebase 驗證整合,為 Cloud Storage 提供強大的使用者驗證機制。這樣就能依據 Firebase 驗證權杖的要求,進行精細的存取權控管。
已驗證的使用者對 Cloud Storage 執行要求時,系統會在 request.auth
變數中填入使用者的 uid
(request.auth.uid
) 和 Firebase 驗證 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; }
群組私人
另一個同樣常見的用途是允許群組對物件的權限,例如允許多個團隊成員協作共用文件。以下是執行此動作的幾種方法:
將這類資料儲存在權杖或檔案中繼資料後,即可在規則內參照該資料:
// 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; }
要求評估
系統會使用傳送至 Cloud Storage 的 request
,評估上傳、下載、中繼資料變更和刪除作業。除了上述 request.auth
物件中使用者的專屬 ID 和 Firebase 驗證酬載外,request
變數也包含執行要求的檔案路徑、接收要求的時間,以及如果要求是寫入,新的 resource
值。
request
物件也包含使用者專屬 ID 和 request.auth
物件中的 Firebase 驗證酬載,我們會在此文件的以使用者為基礎的安全性一節進一步說明。
以下是 request
物件中的完整屬性清單:
屬性 | 類型 | 說明 |
---|---|---|
auth |
map<string, string> | 使用者登入時,請提供 uid 、使用者的專屬 ID 和 token (Firebase 驗證 JWT 憑證附加資訊)。否則為 null 。 |
params |
map<string, string> | 包含要求查詢參數的地圖。 |
path |
路徑 | path ,代表要求執行要求的路徑。 |
resource |
map<string, string> | 新資源值,只會顯示在 write 要求中。 |
time |
時間戳記 | 代表要求評估要求的伺服器時間的時間戳記。 |
資源評估
評估規則時,您可能也會想評估要上傳、下載、修改或刪除檔案的中繼資料。這可讓您建立複雜且強大的規則,例如只允許上傳特定內容類型的檔案,或僅允許刪除超過特定大小的檔案。
Cloud Storage 的 Firebase 安全性規則在 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 |
map<string, string> | 開發人員指定的其他自訂中繼資料鍵/值組合。 |
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 Firestore 函式的 Cloud Storage 安全性規則後,您會在 Firebase 控制台或 Firebase CLI 看到提示,啟用連線這兩項產品的權限。
如要停用這項功能,請按照「管理及部署 Firebase 安全性規則」一文的說明移除 IAM 角色。
驗證資料
您也可以使用 Cloud Storage 的 Firebase 安全性規則驗證資料,包括驗證檔案名稱與路徑,以及檔案中繼資料屬性 (例如 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,則僅限 Cloud Firestore 內建函式,例如get()
和exists()
。 - 函式可能會呼叫其他函式,但可能不會重複。呼叫堆疊總深度上限為 10。
- 在
rules2
版本中,函式可以使用let
關鍵字定義變數。函式可以擁有任意數量的繫結,但結尾必須是傳回陳述式。
以 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 模擬器和專屬的安全性規則測試程式庫測試規則。
- 查看可用於部署規則的方法。