Catch up on highlights from Firebase at Google I/O 2023. Learn more

Firebase 雲存儲安全規則中的使用條件

本指南以學習 Firebase 安全規則語言指南的核心語法為基礎,展示瞭如何向雲存儲的 Firebase 安全規則添加條件。

雲存儲安全規則的主要構建塊是條件。條件是一個布爾表達式,用於確定是允許還是拒絕特定操作。對於基本規則,使用truefalse文字作為條件非常有效。但是 Firebase 雲存儲安全規則語言為您提供了編寫更複雜條件的方法,這些條件可以:

  • 檢查用戶身份驗證
  • 驗證傳入數據

驗證

Firebase 雲存儲安全規則與 Firebase 身份驗證集成,為雲存儲提供強大的基於用戶的身份驗證。這允許基於 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
  • Group private:檢查自定義令牌的聲明以匹配所選聲明,或讀取文件元數據以查看是否存在元數據字段

民眾

任何不考慮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 身份驗證自定義令牌,其中包含有關組成員的附加信息(例如組 ID)
  • 文件元數據中包含組信息(例如組 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;
}

請求評估

使用發送到 Cloud Storage 的request評估上傳、下載、元數據更改和刪除。除瞭如上所述的request.auth對像中的用戶唯一 ID 和 Firebase 身份驗證負載之外, request變量還包含執行請求的文件路徑、收到請求的時間以及新的resource值(如果該請求是一個寫。

request對像還包含用戶的唯一 ID 和request.auth對像中的 Firebase 身份驗證有效負載,這將在文檔的基於用戶的安全部分中進一步解釋。

request對像中的完整屬性列表如下:

財產類型描述
auth地圖<字符串,字符串>當用戶登錄時,提供用戶的唯一 ID uidtoken ,即 Firebase 身份驗證 JWT 聲明的映射。否則,它將為null
params地圖<字符串,字符串>包含請求的查詢參數的映射。
path小路表示正在執行請求的路徑的path
resource地圖<字符串,字符串>新的資源值,僅出現在write請求中。
time時間戳表示請求被評估的服務器時間的時間戳。

資源評估

在評估規則時,您可能還想評估正在上傳、下載、修改或刪除的文件的元數據。這使您可以創建複雜而強大的規則,例如只允許上傳具有特定內容類型的文件,或者只允許刪除大於特定大小的文件。

Cloud Storage 的 Firebase 安全規則在resource對像中提供文件元數據,其中包含 Cloud Storage 對像中顯示的元數據的鍵/值對。可以在readwrite請求時檢查這些屬性以確保數據完整性。

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包含所有這些,但generationmetagenerationetagtimeCreatedupdated除外。

使用 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 中提示您啟用連接這兩個產品的權限。

您可以通過刪除 IAM 角色來禁用該功能,如管理和部署 Firebase 安全規則中所述。

驗證數據

Cloud Storage 的 Firebase 安全規則也可用於數據驗證,包括驗證文件名和路徑以及文件元數據屬性,例如contentTypesize

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 安全規則中使用函數可以使它們更易於維護。

下一步

在討論了條件之後,您對規則有了更深入的了解,並準備好:

了解如何處理核心用例,並了解開發、測試和部署規則的工作流程: