本指南以構建安全規則指南為基礎,展示瞭如何向 Cloud Firestore 安全規則添加條件。如果您不熟悉 Cloud Firestore 安全規則的基礎知識,請參閱入門指南。
Cloud Firestore 安全規則的主要構建塊是條件。條件是一個布爾表達式,用於確定是允許還是拒絕特定操作。使用安全規則編寫檢查用戶身份驗證、驗證傳入數據甚至訪問數據庫其他部分的條件。
驗證
最常見的安全規則模式之一是根據用戶的身份驗證狀態控制訪問。例如,您的應用可能希望僅允許登錄用戶寫入數據:
service cloud.firestore {
match /databases/{database}/documents {
// Allow the user to access documents in the "cities" collection
// only if they are authenticated.
match /cities/{city} {
allow read, write: if request.auth != null;
}
}
}
另一種常見模式是確保用戶只能讀取和寫入他們自己的數據:
service cloud.firestore {
match /databases/{database}/documents {
// Make sure the uid of the requesting user matches name of the user
// document. The wildcard expression {userId} makes the userId variable
// available in rules.
match /users/{userId} {
allow read, update, delete: if request.auth != null && request.auth.uid == userId;
allow create: if request.auth != null;
}
}
}
如果您的應用程序使用 Firebase Authentication 或Google Cloud Identity Platform ,則request.auth
變量包含客戶端請求數據的身份驗證信息。有關request.auth
的更多信息,請參閱參考文檔。
數據驗證
許多應用程序將訪問控制信息存儲為數據庫中文檔的字段。 Cloud Firestore 安全規則可以根據文檔數據動態允許或拒絕訪問:
service cloud.firestore {
match /databases/{database}/documents {
// Allow the user to read data if the document has the 'visibility'
// field set to 'public'
match /cities/{city} {
allow read: if resource.data.visibility == 'public';
}
}
}
resource
變量指的是請求的文檔, resource.data
是存儲在文檔中的所有字段和值的映射。有關resource
變量的更多信息,請參閱參考文檔。
寫入數據時,您可能希望將傳入數據與現有數據進行比較。在這種情況下,如果您的規則集允許掛起的寫入,則request.resource
變量包含文檔的未來狀態。對於僅修改文檔字段子集的update
操作, request.resource
變量將包含操作後的待定文檔狀態。您可以檢查request.resource
中的字段值以防止不需要或不一致的數據更新:
service cloud.firestore {
match /databases/{database}/documents {
// Make sure all cities have a positive population and
// the name is not changed
match /cities/{city} {
allow update: if request.resource.data.population > 0
&& request.resource.data.name == resource.data.name;
}
}
}
訪問其他文件
使用get()
和exists()
函數,您的安全規則可以根據數據庫中的其他文檔評估傳入請求。 get()
和exists()
函數都需要完全指定的文檔路徑。當使用變量為get()
和exists()
構造路徑時,您需要使用$(variable)
語法顯式轉義變量。
在下面的示例中, database
變量由匹配語句match /databases/{database}/documents
捕獲並用於形成路徑:
service cloud.firestore {
match /databases/{database}/documents {
match /cities/{city} {
// Make sure a 'users' document exists for the requesting user before
// allowing any writes to the 'cities' collection
allow create: if request.auth != null && exists(/databases/$(database)/documents/users/$(request.auth.uid))
// Allow the user to delete cities if their user document has the
// 'admin' field set to 'true'
allow delete: if request.auth != null && get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin == true
}
}
}
對於寫入,您可以使用getAfter()
函數在事務或批量寫入完成之後但在事務或批量提交之前訪問文檔的狀態。與get()
一樣, getAfter()
函數採用完全指定的文檔路徑。您可以使用getAfter()
來定義必須作為事務或批處理一起發生的寫入集。
訪問通話限制
每個規則集評估的文檔訪問調用有限制:
- 10 用於單文檔請求和查詢請求。
20 用於多文檔讀取、事務和批量寫入。之前的 10 個限制也適用於每個操作。
例如,假設您創建了一個包含 3 個寫入操作的批處理寫入請求,並且您的安全規則使用 2 個文檔訪問調用來驗證每個寫入。在這種情況下,每個寫入使用其 10 個訪問調用中的 2 個,而批處理的寫入請求使用其 20 個訪問調用中的 6 個。
超過任一限制都會導致權限被拒絕錯誤。某些文檔訪問調用可能會被緩存,緩存的調用不計入限制。
有關這些限制如何影響事務和批量寫入的詳細說明,請參閱保護原子操作指南。
訪問電話和定價
使用這些函數會在您的數據庫中執行讀取操作,這意味著即使您的規則拒絕請求,您也會為讀取文檔付費。有關更具體的結算信息,請參閱Cloud Firestore 定價。
自定義函數
隨著您的安全規則變得越來越複雜,您可能希望將條件集包裝在可以在您的規則集中重複使用的函數中。安全規則支持自定義函數。自定義函數的語法有點像 JavaScript,但安全規則函數是用具有一些重要限制的特定領域語言編寫的:
- 函數只能包含一個
return
語句。它們不能包含任何附加邏輯。例如,它們不能執行循環或調用外部服務。 - 函數可以從定義它們的範圍內自動訪問函數和變量。例如,
service cloud.firestore
範圍內定義的函數可以訪問resource
變量和內置函數,例如get()
和exists()
。 - 函數可以調用其他函數但不能遞歸。總調用堆棧深度限制為 10。
- 在規則版本
v2
中,函數可以使用let
關鍵字定義變量。函數最多可以有 10 個 let 綁定,但必須以 return 語句結尾。
函數使用function
關鍵字定義,並接受零個或多個參數。例如,您可能希望將上面示例中使用的兩種類型的條件組合到一個函數中:
service cloud.firestore {
match /databases/{database}/documents {
// 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 /cities/{city} {
allow read, write: if signedInOrPublic();
}
match /users/{user} {
allow read, write: if signedInOrPublic();
}
}
}
隨著規則復雜性的增加,在安全規則中使用函數可以使它們更易於維護。
規則不是過濾器
一旦保護了數據並開始編寫查詢,請記住安全規則不是過濾器。您不能為集合中的所有文檔編寫查詢並期望 Cloud Firestore 僅返回當前客戶端有權訪問的文檔。
例如,採用以下安全規則:
service cloud.firestore {
match /databases/{database}/documents {
// Allow the user to read data if the document has the 'visibility'
// field set to 'public'
match /cities/{city} {
allow read: if resource.data.visibility == 'public';
}
}
}
拒絕:此規則拒絕以下查詢,因為結果集可能包含visibility
不public
文檔:
網絡
db.collection("cities").get() .then(function(querySnapshot) { querySnapshot.forEach(function(doc) { console.log(doc.id, " => ", doc.data()); }); });
Allowed :此規則允許以下查詢,因為where("visibility", "==", "public")
子句保證結果集滿足規則的條件:
網絡
db.collection("cities").where("visibility", "==", "public").get() .then(function(querySnapshot) { querySnapshot.forEach(function(doc) { console.log(doc.id, " => ", doc.data()); }); });
Cloud Firestore 安全規則根據每個查詢的潛在結果評估每個查詢,如果它可以返回客戶端無權讀取的文檔,則請求失敗。查詢必須遵循您的安全規則設置的約束。有關安全規則和查詢的更多信息,請參閱安全查詢數據。
下一步
- 了解安全規則如何影響您的查詢。
- 了解如何構建安全規則。
- 閱讀安全規則參考。
- 對於使用 Cloud Storage for Firebase 的應用,了解如何編寫訪問 Cloud Firestore 文檔的 Cloud Storage 安全規則條件。