本頁面僅以
建立安全性規則和
請參閱「編寫安全性規則的條件」一文,瞭解
「Cloud Firestore Security Rules」會與查詢互動。進一步說明
安全性規則會影響您可以撰寫的查詢,並說明如何確保
查詢和安全性規則的限制相同。這個頁面也包含
說明如何編寫安全性規則,以依據查詢允許或拒絕查詢
limit
和 orderBy
等屬性。
規則不是篩選器
編寫擷取文件的查詢時,請記得安全性規則 非篩選條件 — 查詢的全為或沒有任何項目。為節省您的時間和資源,Cloud Firestore 會根據潛在的結果集評估查詢,而不是所有文件的實際欄位值。如果查詢作業 可能會傳回用戶端無權讀取的文件 整個要求都會失敗
查詢和安全性規則
如以下範例所示,您必須編寫符合安全性規則限制的查詢。
根據auth.uid
保護文件並查詢文件
以下範例說明如何撰寫查詢以擷取文件
並受到安全性規則保護假設資料庫包含
story
份文件:
/story/{storyid}
{
title: "A Great Story",
content: "Once upon a time...",
author: "some_auth_id",
published: false
}
除了 title
和 content
欄位以外,每份文件都會儲存
用於存取權控管的 author
和 published
欄位。這些範例假設
應用程式使用 Firebase 驗證來設定 author
欄位
附加至文件建立使用者 UID。Firebase 認證也會在安全性規則中填入 request.auth
變數。
下列安全性規則使用request.auth
和
resource.data
變數,限制每個項目的讀取和寫入權限
story
傳送給作者:
service cloud.firestore {
match /databases/{database}/documents {
match /stories/{storyid} {
// Only the authenticated user who authored the document can read or write
allow read, write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
假設您的應用程式含有向使用者顯示 story
清單的頁面
一般文件。您應該可以使用下列
要填入這個頁面的內容然而,這項查詢將會失敗
包括和安全性規則相同的限制:
無效:查詢限制條件不符合安全規則限制
// This query will fail
db.collection("stories").get()
即使目前的使用者實際上是您所有
story
文件。出現這個行為的原因是
「Cloud Firestore」套用你的安全性規則,之後會評估查詢
比對結果的「可能」結果集,而不是「實際」屬性
資料庫內的文件如果查詢可以「可能」包含文件
否則查詢就會失敗。
相反地,以下查詢會成功,因為它在 author
欄位上包含與安全性規則相同的限制條件:
有效:查詢限制符合安全性 規則限制
var user = firebase.auth().currentUser;
db.collection("stories").where("author", "==", user.uid).get()
依據欄位保護文件並查詢文件
為進一步說明查詢和規則之間的互動關係,下方的安全性規則會擴充 stories
集合的讀取權限,讓任何使用者都能讀取 story
文件,前提是 published
欄位設為 true
。
service cloud.firestore {
match /databases/{database}/documents {
match /stories/{storyid} {
// Anyone can read a published story; only story authors can read unpublished stories
allow read: if resource.data.published == true || (request.auth != null && request.auth.uid == resource.data.author);
// Only story authors can write
allow write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
已發布網頁的查詢必須包含與安全性相同的限制 規則:
db.collection("stories").where("published", "==", true).get()
查詢限制 .where("published", "==", true)
可保證
在任何結果中,resource.data.published
為 true
。因此,這個查詢
符合安全性規則,並允許讀取資料。
OR
個查詢
評估邏輯 OR
查詢時 (or
、in
或 array-contains-any
)
依據規則集,Cloud Firestore 會評估每個比較值
。每個比較值都必須符合安全性規則限制。適用對象
舉例來說
規則:
match /mydocuments/{doc} {
allow read: if resource.data.x > 5;
}
無效:查詢不保證
所有可能文件的x > 5
// These queries will fail
query(db.collection("mydocuments"),
or(where("x", "==", 1),
where("x", "==", 6)
)
)
query(db.collection("mydocuments"),
where("x", "in", [1, 3, 6, 42, 99])
)
有效:查詢可確保所有潛在文件的 x > 5
query(db.collection("mydocuments"),
or(where("x", "==", 6),
where("x", "==", 42)
)
)
query(db.collection("mydocuments"),
where("x", "in", [6, 42, 99, 105, 200])
)
評估查詢限制
您的安全性規則也可以根據限制來接受或拒絕查詢。
request.query
變數包含 limit
、offset
、
和 orderBy
屬性例如您的安全性規則
可以拒絕任何不會限製文件數量上限的查詢
擷取到特定範圍:
allow list: if request.query.limit <= 10;
下列規則集示範如何編寫用以評估安全規則
對查詢設下限制此範例會擴充前一個 stories
同時進行下列變更:
- 規則集會將讀取規則拆分為
get
和list
的規則。 get
規則會限制單一文件的擷取作業,僅限於公用文件或使用者撰寫的文件。list
規則套用與get
相同的限制,但適用於查詢。這項服務 也會檢查查詢限制,然後拒絕任何沒有限制的查詢,或 建議大於 10- 規則集定義了
authorOrPublished()
函式來避免編寫程式碼 重複內容
service cloud.firestore {
match /databases/{database}/documents {
match /stories/{storyid} {
// Returns `true` if the requested story is 'published'
// or the user authored the story
function authorOrPublished() {
return resource.data.published == true || request.auth.uid == resource.data.author;
}
// Deny any query not limited to 10 or fewer documents
// Anyone can query published stories
// Authors can query their unpublished stories
allow list: if request.query.limit <= 10 &&
authorOrPublished();
// Anyone can retrieve a published story
// Only a story's author can retrieve an unpublished story
allow get: if authorOrPublished();
// Only a story's author can write to a story
allow write: if request.auth.uid == resource.data.author;
}
}
}
集合群組查詢和安全性規則
根據預設,查詢的範圍僅限於單一集合,且會擷取結果 而非該集合。取代為 集合群組查詢 擷取結果集合群組的結果,集合群組內有所有含有 相同的 ID。本節說明如何保護集合群組查詢 安全規則
根據集合群組保護文件並查詢文件
在安全性規則中,您必須明確允許 為集合群組編寫規則,藉此建立集合群組查詢:
- 請確定
rules_version = '2';
是規則集的第一行。集合 群組查詢必須使用 新的週期性萬用字元{name=**}
安全性行為 規則版本 2 - 為產品素材資源集合群組撰寫規則
match /{path=**}/[COLLECTION_ID]/{doc}
。
舉例來說,假設論壇以 forum
文件的形式進行組織,其中包含 posts
子集合:
/forums/{forumid}/posts/{postid}
{
author: "some_auth_id",
authorname: "some_username",
content: "I just read a great story.",
}
在這個應用程式中,我們開放文章擁有者編輯及閱讀 已通過驗證的使用者:
service cloud.firestore {
match /databases/{database}/documents {
match /forums/{forumid}/posts/{post} {
// Only authenticated users can read
allow read: if request.auth != null;
// Only the post author can write
allow write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
任何經過驗證的使用者都可以擷取任一論壇的貼文:
db.collection("forums/technology/posts").get()
不過,如果您想在所有論壇中顯示目前使用者張貼的訊息,該怎麼做?
您可以使用集合群組查詢來擷取
所有「posts
」集合的結果:
var user = firebase.auth().currentUser;
db.collectionGroup("posts").where("author", "==", user.uid).get()
在安全性規則中,您必須允許這項查詢,方法如下:
為 posts
集合群組編寫讀取或清單規則:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Authenticated users can query the posts collection group
// Applies to collection queries, collection group queries, and
// single document retrievals
match /{path=**}/posts/{post} {
allow read: if request.auth != null;
}
match /forums/{forumid}/posts/{postid} {
// Only a post's author can write to a post
allow write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
但請注意,這些規則會套用至 ID 為 posts
的所有產品素材資源集合。
不論階層為何舉例來說,這些規則適用於下列所有項目
posts
集合:
/posts/{postid}
/forums/{forumid}/posts/{postid}
/forums/{forumid}/subforum/{subforumid}/posts/{postid}
基於欄位的安全集合群組查詢
與單一集合查詢一樣,集合群組查詢也必須符合安全性規則設定的限制。舉例來說,我們可以新增 published
] 欄位加入每個論壇文章,就和在上述 stories
範例中的做法一樣:
/forums/{forumid}/posts/{postid}
{
author: "some_auth_id",
authorname: "some_username",
content: "I just read a great story.",
published: false
}
然後,我們可以根據以下規則為 posts
集合群組撰寫規則
published
狀態以及貼文 author
:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Returns `true` if the requested post is 'published'
// or the user authored the post
function authorOrPublished() {
return resource.data.published == true || request.auth.uid == resource.data.author;
}
match /{path=**}/posts/{post} {
// Anyone can query published posts
// Authors can query their unpublished posts
allow list: if authorOrPublished();
// Anyone can retrieve a published post
// Authors can retrieve an unpublished post
allow get: if authorOrPublished();
}
match /forums/{forumid}/posts/{postid} {
// Only a post's author can write to a post
allow write: if request.auth.uid == resource.data.author;
}
}
}
透過這些規則,網頁、Apple 和 Android 用戶端可以進行下列查詢:
任何人都能在論壇中擷取已發布的貼文:
db.collection("forums/technology/posts").where('published', '==', true).get()
所有人都可擷取作者在所有論壇中發布的貼文:
db.collectionGroup("posts").where("author", "==", "some_auth_id").where('published', '==', true).get()
作者可擷取自己在所有平台上已發布和未發布的文章 論壇:
var user = firebase.auth().currentUser; db.collectionGroup("posts").where("author", "==", user.uid).get()
依集合群組和文件路徑保護文件並查詢文件
在某些情況下,您可能會想根據 。如要建立限制,可以使用 依據欄位保護及查詢文件。
假設應用程式可以追蹤每位使用者的交易 數量:
/users/{userid}/Exchange/{Exchangeid}/transactions/{transaction}
{
amount: 100,
exchange: 'some_exchange_name',
timestamp: April 1, 2019 at 12:00:00 PM UTC-7,
user: "some_auth_id",
}
請注意 user
欄位。即使我們知道哪個使用者擁有 transaction
則會在文件路徑中複製這項資訊
transaction
文件,是因為可以讓我們進行兩件事:
寫入僅限含有下列內容的文件的集合群組查詢: 特定
/users/{userid}
。例如:var user = firebase.auth().currentUser; // Return current user's last five transactions across all exchanges db.collectionGroup("transactions").where("user", "==", user).orderBy('timestamp').limit(5)
對「
transactions
」集合中的所有查詢強制執行這項限制 群組,因此某個使用者無法擷取其他使用者的transaction
文件。
我們會在安全性規則中強制執行這項限制,並為 user
欄位加入資料驗證:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{path=**}/transactions/{transaction} {
// Authenticated users can retrieve only their own transactions
allow read: if resource.data.user == request.auth.uid;
}
match /users/{userid}/exchange/{exchangeid}/transactions/{transaction} {
// Authenticated users can write to their own transactions subcollections
// Writes must populate the user field with the correct auth id
allow write: if userid == request.auth.uid && request.data.user == request.auth.uid
}
}
}
後續步驟
- 如需角色型存取控制的詳細範例,請參閱「保護使用者和群組的資料存取權」。
- 閱讀安全性規則參考資料。