В этой статье мы опираемся на концепции, описанные в статьях Структурирование правил безопасности и Написание условий для правил безопасности, чтобы объяснить, как Cloud Firestore Security Rules взаимодействуют с запросами. В ней подробно рассматривается, как правила безопасности влияют на запросы, которые вы можете писать, и описывается, как обеспечить использование в ваших запросах тех же ограничений, что и в правилах безопасности. На этой странице также описывается, как написать правила безопасности, чтобы разрешить или запретить запросы на основе свойств запроса, таких как limit и orderBy.
Запрос к ИИ для получения помощи от ИИ
Чтобы получить помощь от ИИ, скопируйте запрос ниже и вставьте его в свой ИИ-агент для программирования (например, Gemini в Android Studio, 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 Authentication, чтобы задать для поля 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. Причина такого поведения заключается в том, что когда
Rules применяет ваши правила безопасности, он оценивает запрос
по его потенциальному набору результатов, а не по фактическим свойствам
документов в вашей базе данных. Если запрос потенциально может включать документы, нарушающие правила безопасности, он не будет выполнен.
А вот этот запрос будет выполнен, потому что в нем есть то же ограничение для поля 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) в отношении набора правил каждое значение сравнения оценивается отдельно. Каждое значение сравнения должно соответствовать ограничениям правила безопасности. Например, для следующего правила:
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;
}
}
}
Запросы к группам коллекций и правила безопасности
По умолчанию запросы ограничены одной коллекцией и получают результаты только из нее. С помощью запросов к группе коллекций можно получать результаты из группы, состоящей из всех коллекций с одинаковым идентификатором. В этом разделе описывается, как защитить запросы группы коллекций с помощью правил безопасности.
Защита документов и выполнение запросов к ним на основе групп коллекций
В правилах безопасности необходимо явно разрешить запросы к группе коллекций, написав правило для группы коллекций:
- Убедитесь, что
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;
}
}
}
Однако обратите внимание, что эти правила будут применяться ко всем коллекциям с идентификатором 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;
}
}
}
С этими правилами клиенты Web, 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
}
}
}
Дальнейшие действия
- Более подробный пример контроля доступа на основе ролей приведен в статье Защита доступа к данным для пользователей и групп.
- Ознакомьтесь со справочником по правилам безопасности.