在 Firebase Cloud Storage 安全性規則中使用條件

本指南以「瞭解 Firebase Security Rules 語言的核心語法」指南為基礎,說明如何在 Firebase Security Rules 中為 Cloud Storage 新增條件。

Cloud Storage Security Rules 的主要建構區塊是「條件」。條件是布林運算式,可決定是否允許或拒絕特定作業。對於基本規則,使用 truefalse 常值做為條件就已足夠。不過,Firebase Security Rules 語言的 Cloud Storage 可讓您編寫更複雜的條件,例如:

  • 檢查使用者驗證
  • 驗證連入資料

驗證

Firebase Security Rules 可與 Firebase Authentication 整合,為 Cloud Storage 提供強大的使用者身分驗證功能。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 變數,因此您只需要檢查 request.auth 變數是否存在,即可要求驗證:null

// 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 Authentication 自訂權杖,內含群組成員的其他資訊 (例如群組 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 Storagerequest 評估上傳、下載、中繼資料變更和刪除作業。除了使用者的專屬 ID 和上述 request.auth 物件中的 Firebase Authentication 酬載之外,request 變數還包含執行要求的檔案路徑、收到要求的時間,以及要求是否為寫入作業,如果是,則包含新的 resource 值。

request 物件也包含使用者的專屬 ID,以及 request.auth 物件中的 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 時間戳記 時間戳記,代表評估要求時的伺服器時間。

資源評估

評估規則時,您可能也想評估上傳、下載、修改或刪除檔案的中繼資料。這可讓您建立複雜且強大的規則,例如只允許上傳特定內容類型的檔案,或只允許刪除大於特定大小的檔案。

Firebase Security RulesCloud Storage 提供 resource 物件中的檔案中繼資料,其中包含 Cloud Storage 物件中顯示的中繼資料鍵/值組合。您可以在 readwrite 要求中檢查這些屬性,確保資料完整性。

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 包含所有這些項目,但 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 Security Rules 後,系統會在 Firebase 控制台或 Firebase CLI 中提示您啟用權限,以連結這兩項產品。

如要停用這項功能,請按照「管理及部署Firebase Security Rules」一文的說明移除 IAM 角色。

驗證資料

Firebase Security Rules Cloud Storage 也可用於資料驗證,包括驗證檔案名稱和路徑,以及 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 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 中使用函式,可讓規則更易於維護,因為規則的複雜度會不斷增加。

後續步驟

討論完條件後,您對規則的瞭解會更深入,並可開始:

瞭解如何處理核心用途,以及開發、測試及部署規則的工作流程: