本指南以學習 Firebase 安全規則語言指南的核心語法為基礎,展示如何為 Firebase 雲端儲存安全規則新增條件。
雲端儲存安全規則的主要組成部分是條件。條件是一個布林表達式,用於確定是否應允許或拒絕特定操作。對於基本規則,使用true
和false
文字作為條件效果非常好。但是 Firebase 雲端儲存安全規則語言為您提供了編寫更複雜條件的方法,這些條件可以:
- 檢查使用者身份驗證
- 驗證傳入數據
驗證
Firebase Cloud Storage 安全規則與 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
物件還包含request.auth
物件中使用者的唯一 ID 和 Firebase 驗證有效負載,這將在文件的基於使用者的安全性部分中進一步解釋。
下面提供了request
物件中屬性的完整清單:
財產 | 類型 | 描述 |
---|---|---|
auth | 地圖<字串,字串> | 當使用者登入時,提供uid (使用者的唯一 ID)和token (Firebase 驗證 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 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 模擬器和專用安全規則測試庫測試規則。
- 查看可用於部署規則的方法。