本頁面以「建構安全性規則」和「編寫安全性規則條件」中的概念為基礎,說明 Cloud Firestore Security Rules 如何與查詢互動。本節將進一步探討安全性規則如何影響可編寫的查詢,並說明如何確保查詢使用與安全性規則相同的限制。本頁也說明如何編寫安全性規則,根據 limit 和 orderBy 等查詢屬性允許或拒絕查詢。
AI 輔助功能的 AI 提示
如需 AI 輔助,請將下方提示詞複製到 AI 程式設計代理 (例如 Android Studio 內建 Gemini、Antigravity、Claude Code、Codex 和 Cursor)。您可以自訂提示,並與代理反覆調整。如需詳細安裝資訊,請參閱 Firebase 代理技能。
Help me use Firebase in my app.
1. Make sure that **Firebase agent skills** are installed and updated. For Claude Code, Codex, or Cursor agents, help me install the Firebase plugin. For other agents, run `npx skills add firebase/agent-skills`. Always try to use **Firebase agent skills** for Firebase-related tasks.
2. Help me write, validate, and deploy Firebase Security Rules to protect my app's Firestore data.
規則不是篩選器
編寫查詢來擷取文件時,請注意安全性規則並非篩選器,查詢結果只有全部符合或全部不符合。為節省時間和資源,規則會根據潛在結果集評估查詢,而非所有文件的實際欄位值。如果查詢可能傳回用戶端無權讀取的文件,整個要求就會失敗。
查詢和安全性規則
如下列範例所示,您必須按照安全性規則的限制編寫查詢。
依據auth.uid保護及查詢文件
以下範例說明如何編寫查詢,擷取受安全性規則保護的文件。假設資料庫包含 story 文件集合:
/stories/{storyid}
{
title: "A Great Story",
content: "Once upon a time...",
author: "some_auth_id",
published: false
}
除了 title 和 content 欄位外,每份文件都會儲存 author 和 published 欄位,用於存取控管。這些範例假設應用程式使用 Firebase 驗證,將 author 欄位設為建立文件的使用者 UID。Firebase Authentication 也會在安全性規則中填入 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 文件的作者,查詢也會失敗。之所以會出現這種行為,是因為規則套用安全性規則時,會根據「潛在」結果集評估查詢,而不是根據資料庫中文件的「實際」屬性。如果查詢「可能」包含違反安全性規則的文件,查詢就會失敗。
相較之下,下列查詢會成功,因為它對 author 欄位包含與安全性規則相同的限制:
有效:查詢限制與安全性規則限制相符
var user = firebase.auth().currentUser;
db.collection("stories").where("author", "==", user.uid).get()
依據欄位保護及查詢文件
為了進一步示範查詢和規則之間的互動,下列安全性規則擴充了 stories 集合的讀取權限,允許任何使用者讀取 published 欄位設為 true 的 story 文件。
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) 時,規則會分別評估每個比較值。每個比較值都必須符合安全性規則限制。舉例來說,以下列規則為例:
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';是規則集的第一行。集合群組查詢需要安全性規則第 2 版的新遞迴萬用字元{name=**}行為。 - 使用
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
}
接著,我們可以根據 published 狀態和貼文 author,為 posts 集合群組編寫規則:
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
}
}
}
後續步驟
- 如需角色式存取控管的詳細範例,請參閱「保護使用者和群組的資料存取權」。
- 請參閱安全性規則參考資料。