Как писать условия для правил безопасности Cloud Firestore

В этом руководстве, основанном на статье Структурирование правил безопасности, рассказывается, как добавлять условия в Cloud Firestore Security Rules. Если вы не знакомы с основами Cloud Firestore Security Rules, ознакомьтесь с руководством по началу работы.

Основной элемент Cloud Firestore Security Rules – это условие. Условие – это логическое выражение, которое определяет, разрешена или запрещена определенная операция. С помощью правил безопасности можно задавать условия, которые проверяют аутентификацию пользователей, подтверждают входящие данные или даже получают доступ к другим частям базы данных.

Чтобы получить помощь от ИИ, скопируйте запрос ниже и вставьте его в ИИ-агент для программирования, например 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.

Аутентификация

Один из наиболее распространенных шаблонов правил безопасности – управление доступом на основе состояния аутентификации пользователя. Например, вы можете разрешить запись данных только пользователям, выполнившим вход:

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 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).

В примере ниже переменная 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) также применяется к каждой операции.

    Например, вы создаете пакетный запрос на запись с тремя операциями записи, а правила безопасности используют два вызова доступа к документам для проверки каждой записи. В этом случае каждая запись использует 2 из 10 вызовов доступа, а пакетный запрос на запись – 6 из 20 вызовов доступа.

При превышении любого из этих ограничений возникает ошибка отказа в доступе. Некоторые вызовы доступа к документам могут кешироваться и не учитываться в лимитах.

Подробное объяснение того, как эти ограничения влияют на транзакции и пакетные записи, см. в руководстве по защите атомарных операций.

Доступ к вызовам и ценам

При использовании этих функций в базе данных выполняется операция чтения, а значит, с вас будет взиматься плата за чтение документов, даже если правила отклонят запрос. Подробную информацию о ценах вы найдете в статье Цены на правила.

Пользовательские функции

По мере усложнения правил безопасности вы можете захотеть обернуть наборы условий в функции, которые можно повторно использовать в наборе правил. Правила безопасности поддерживают пользовательские функции. Синтаксис пользовательских функций похож на 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();
    }
  }
}

Использование функций в правилах безопасности упрощает их поддержку по мере усложнения правил.

Правила – это не фильтры

После того, как вы защитите свои данные и начнете писать запросы, помните, что правила безопасности не являются фильтрами. Вы не можете написать запрос для всех документов в коллекции и ожидать, что правила вернут только те документы, к которым у текущего клиента есть разрешение на доступ.

Рассмотрим следующее правило безопасности:

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());
        });
    });

Правила безопасности оценивают каждый запрос по его потенциальному результату и отклоняют запрос, если он может вернуть документ, на чтение которого у клиента нет разрешения. Запросы должны соответствовать ограничениям, установленным вашими правилами безопасности. Подробнее о правилах безопасности и запросах…

Дальнейшие действия