本指南將延續「瞭解 Firebase Security Rules 語言的核心語法」指南,說明如何在 Cloud Storage 的 Firebase Security Rules 中加入條件。
Cloud Storage Security Rules 的主要建構區塊是條件。條件是一種布林值運算式,可判定是否應允許或拒絕特定作業。對於基本規則,使用 true
和 false
常值做為條件非常合適。不過,Cloud Storage 語言的 Firebase Security Rules 可讓您編寫更複雜的條件,以便:
- 檢查使用者驗證
- 驗證傳入的資料
驗證
Cloud Storage 適用的 Firebase Security Rules 與 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; }
私人群組
另一個同樣常見的用途是允許在物件上設定群組權限,例如允許多位團隊成員在共用文件上協同合作。以下是執行此動作的幾種方法:
這項資料儲存在符記或檔案中繼資料後,即可在規則中參照:
// 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
來評估上傳、下載、中繼資料變更和刪除作業。除了使用者不重複 ID 和 request.auth
物件中的 Firebase Authentication 酬載 (如上所述),request
變數還包含執行要求的檔案路徑、收到要求的時間,以及要求為寫入時的新 resource
值。
request
物件也會在 request.auth
物件中包含使用者的專屬 ID 和 Firebase Authentication 酬載,我們會在文件的「使用者層級安全性」一節進一步說明。
以下是 request
物件中的完整屬性清單:
屬性 | 類型 | 說明 |
---|---|---|
auth |
map<string, string> | 使用者登入時,請提供 uid 、使用者的專屬 ID 和 token (Firebase Authentication JWT 憑證附加資訊對應)。否則為 null 。 |
params |
map<string, string> | 包含要求查詢參數的對應項目。 |
path |
路徑 | path ,代表要求執行要求的路徑。 |
resource |
map<string, string> | 新資源值,只會顯示在 write 要求中。 |
time |
時間戳記 | 代表要求評估時間的時間戳記。 |
資源評估
評估規則時,您可能也會想評估要上傳、下載、修改或刪除檔案的中繼資料。這可讓您建立複雜且強大的規則,例如只允許上傳特定內容類型的檔案,或僅允許刪除超過特定大小的檔案。
Cloud Storage 的 Firebase Security Rules 會在 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 Security Rules 後,系統會在 Firebase 控制台或 Firebase CLI 中提示您啟用連結這兩個產品的權限。
如要停用這項功能,請移除 IAM 角色,如「管理及部署 Firebase Security Rules」一文所述。
驗證資料
Cloud Storage 的 Firebase Security Rules 也可用於資料驗證,包括驗證檔案名稱和路徑,以及檔案中繼資料屬性,例如 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 Security Rules 變得越來越複雜,您可能會想在函式中包裝一組條件,以便在規則集上重複使用。安全性規則支援自訂函式。自訂函式的語法有點類似 JavaScript,但 Firebase Security Rules 函式是使用特定領域語言編寫,因此有以下幾項重要限制:
- 函式只能包含單一
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 Security Rules 中使用函式,可讓規則在複雜度增加時更容易維護。
後續步驟
在討論條件之後,您對規則的瞭解更加精細,就可以開始:
瞭解如何處理核心用途,並瞭解開發、測試及部署規則的工作流程:
- 編寫規則來處理常見情境。
- 查看您必須找出並避免不安全的規則的情況,進一步累積知識。
- 使用 Cloud Storage 模擬器和專屬的安全性規則測試程式庫測試規則。
- 查看部署 Rules 可用的各項方法。