本指南將建構在「建立安全性規則」指南之上,說明如何在 Cloud Firestore Security Rules 中新增條件。如果您不熟悉 Cloud Firestore Security Rules 的基礎知識,請參閱入門指南。
Cloud Firestore Security Rules 的主要建構區塊是條件。條件是布林值運算式,可決定是否應允許或拒絕特定作業。使用安全性規則編寫條件,檢查使用者驗證、驗證傳入的資料,甚至存取資料庫的其他部分。
驗證
最常見的安全規則模式之一,就是根據使用者的驗證狀態控管存取權。舉例來說,您的應用程式可能只想允許已登入的使用者寫入資料:
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 驗證或 Google Cloud Identity Platform,request.auth
變數會包含要求資料的用戶端驗證資訊。如要進一步瞭解 request.auth
,請參閱參考說明文件。
驗證資料
許多應用程式會將存取權控管資訊儲存為資料庫中文件的欄位。Cloud Firestore Security Rules 可根據文件資料動態允許或拒絕存取權:
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)
語法明確轉義變數。
在以下範例中,系統會使用比對陳述式 match /databases/{database}/documents
擷取 database
變數,並用於形成路徑:
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 項文件存取呼叫來驗證各項寫入作業。在這種情況下,每項寫入作業會使用 2 個存取呼叫 (共 10 個),而批次寫入要求則會使用 6 個存取呼叫 (共 20 個)。
超過任一項限制都會引發權限遭拒的錯誤。系統可能會快取部分的文件存取呼叫,已快取的呼叫不會計入限制中。
如要進一步瞭解這些限制如何影響交易和批次寫入作業,請參閱保護原子作業指南。
存取通話和定價
使用這些函式會在資料庫中執行讀取作業,這表示即使規則拒絕要求,您仍會因讀取文件而產生費用。如需更詳細的帳單資訊,請參閱「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()); }); });
允許:此規則允許下列查詢,因為 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 Security Rules 條件。