Catch up on everything announced at Firebase Summit, and learn how Firebase can help you accelerate app development and run your app with confidence. Learn More

Проверьте свои правила безопасности Cloud Firestore

Оптимизируйте свои подборки Сохраняйте и классифицируйте контент в соответствии со своими настройками.

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

Быстрый старт

Несколько базовых тестов с простыми правилами можно найти в примере быстрого запуска .

Понимание правил безопасности Cloud Firestore

Реализуйте Firebase Authentication и правила безопасности Cloud Firestore для бессерверной аутентификации, авторизации и проверки данных при использовании библиотек мобильных и веб-клиентов.

Правила безопасности Cloud Firestore включают две части:

  1. Оператор match , который идентифицирует документы в вашей базе данных.
  2. allow выражение, управляющее доступом к этим документам.

Firebase Authentication проверяет учетные данные пользователей и обеспечивает основу для систем доступа на основе пользователей и ролей.

Каждый запрос к базе данных из библиотеки мобильных/веб-клиентов Cloud Firestore оценивается в соответствии с вашими правилами безопасности перед чтением или записью каких-либо данных. Если правила запрещают доступ к любому из указанных путей к документам, весь запрос завершается ошибкой.

Узнайте больше о правилах безопасности Cloud Firestore в статье Начало работы с правилами безопасности Cloud Firestore .

Установите эмулятор

Чтобы установить эмулятор Cloud Firestore, используйте интерфейс командной строки Firebase и выполните следующую команду:

firebase setup:emulators:firestore

Запустите эмулятор

Начните с инициализации проекта Firebase в вашем рабочем каталоге. Это стандартный первый шаг при использовании интерфейса командной строки Firebase .

firebase init

Запустите эмулятор с помощью следующей команды. Эмулятор будет работать до тех пор, пока вы не завершите процесс:

firebase emulators:start --only firestore

Во многих случаях требуется запустить эмулятор, выполнить набор тестов, а затем закрыть эмулятор после выполнения тестов. Вы можете легко сделать это с помощью команды emulators:exec :

firebase emulators:exec --only firestore "./my-test-script.sh"

При запуске эмулятор попытается запустить порт по умолчанию (8080). Вы можете изменить порт эмулятора, изменив раздел "emulators" вашего файла firebase.json :

{
  // ...
  "emulators": {
    "firestore": {
      "port": "YOUR_PORT"
    }
  }
}

Перед запуском эмулятора

Прежде чем начать использовать эмулятор, имейте в виду следующее:

  • Сначала эмулятор загрузит правила, указанные в поле firestore.rules вашего файла firebase.json . Он ожидает имя локального файла, содержащего ваши правила безопасности Cloud Firestore, и применяет эти правила ко всем проектам. Если вы не укажете локальный путь к файлу или не используете метод loadFirestoreRules , как описано ниже, эмулятор рассматривает все проекты как имеющие открытые правила.
  • Хотя большинство Firebase SDK работают с эмуляторами напрямую, только библиотека @firebase/rules-unit-testing поддерживает имитацию auth в правилах безопасности, что значительно упрощает модульные тесты. Кроме того, библиотека поддерживает несколько специфичных для эмулятора функций, таких как очистка всех данных, как указано ниже.
  • Эмуляторы также будут принимать рабочие токены Firebase Auth, предоставленные через клиентские SDK, и соответствующим образом оценивать правила, что позволяет напрямую подключать ваше приложение к эмуляторам при интеграции и ручных тестах.

Запуск локальных модульных тестов

Запускайте локальные модульные тесты с помощью пакета SDK для JavaScript версии 9.

Firebase распространяет библиотеку модульного тестирования правил безопасности как с SDK JavaScript версии 9, так и с SDK версии 8. API-интерфейсы библиотек существенно отличаются. Мы рекомендуем тестовую библиотеку v9, которая более оптимизирована и требует меньше настроек для подключения к эмуляторам и, таким образом, безопасно предотвращает случайное использование производственных ресурсов. Для обратной совместимости мы продолжаем делать доступной библиотеку тестирования v8 .

Используйте модуль @firebase/rules-unit-testing для взаимодействия с эмулятором, работающим локально. Если вы получаете тайм-ауты или ошибки ECONNREFUSED , дважды проверьте, действительно ли работает эмулятор.

Мы настоятельно рекомендуем использовать последнюю версию Node.js, чтобы вы могли использовать нотацию async/await . Почти все поведение, которое вы, возможно, захотите протестировать, связано с асинхронными функциями, а модуль тестирования предназначен для работы с кодом на основе Promise.

Библиотека модульного тестирования правил версии 9 всегда осведомлена об эмуляторах и никогда не затрагивает ваши производственные ресурсы.

Вы импортируете библиотеку, используя модульные операторы импорта v9. Например:

import {
  assertFails,
  assertSucceeds,
  initializeTestEnvironment,
  RulesTestEnvironment,
} from "@firebase/rules-unit-testing"

// Use `const { … } = require("@firebase/rules-unit-testing")` if imports are not supported
// Or we suggest `const testing = require("@firebase/rules-unit-testing")` if necessary.

После импорта реализация модульных тестов включает в себя:

  • Создание и настройка RulesTestEnvironment с вызовом initializeTestEnvironment .
  • Настройка тестовых данных без активации правил с помощью удобного метода, позволяющего временно их обойти, RulesTestEnvironment.withSecurityRulesDisabled .
  • Настройка набора тестов и хуков до/после каждого теста с вызовами для очистки тестовых данных и среды, например RulesTestEnvironment.cleanup() или RulesTestEnvironment.clearFirestore() .
  • Реализация тестовых случаев, имитирующих состояния аутентификации, с использованием RulesTestEnvironment.authenticatedContext и RulesTestEnvironment.unauthenticatedContext .

Общие методы и служебные функции

Также см. методы тестирования для конкретных эмуляторов в v9 SDK .

initializeTestEnvironment() => RulesTestEnvironment

Эта функция инициализирует тестовую среду для модульного тестирования правил. Сначала вызовите эту функцию для настройки теста. Для успешного выполнения требуется, чтобы эмуляторы были запущены.

Функция принимает необязательный объект, определяющий TestEnvironmentConfig , который может состоять из идентификатора проекта и параметров конфигурации эмулятора.

let testEnv = await initializeTestEnvironment({
  projectId: "demo-project-1234",
  firestore: {
    rules: fs.readFileSync("firestore.rules", "utf8"),
  },
});

RulesTestEnvironment.authenticatedContext({ user_id: string, tokenOptions?: TokenOptions }) => RulesTestContext

Этот метод создает RulesTestContext , который ведет себя как аутентифицированный пользователь аутентификации. Запросы, созданные с помощью возвращенного контекста, будут иметь прикрепленный токен фиктивной аутентификации. При необходимости передайте объект, определяющий настраиваемые утверждения или переопределения полезных данных токена проверки подлинности.

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

// Assuming a Firestore app and the Firestore emulator for this example
import { setDoc } from "firebase/firestore";

const alice = testEnv.authenticatedContext("alice", { … });
// Use the Firestore instance associated with this context
await assertSucceeds(setDoc(alice.firestore(), '/users/alice'), { ... });

RulesTestEnvironment.unauthenticatedContext() => RulesTestContext

Этот метод создает RulesTestContext , который ведет себя как клиент, не вошедший в систему через аутентификацию. Запросы, созданные через возвращенный контекст, не будут иметь присоединенных токенов Firebase Auth.

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

// Assuming a Cloud Storage app and the Storage emulator for this example
import { getStorage, ref, deleteObject } from "firebase/storage";

const alice = testEnv.unauthenticatedContext();

// Use the Cloud Storage instance associated with this context
const desertRef = ref(alice.storage(), 'images/desert.jpg');
await assertSucceeds(deleteObject(desertRef));

RulesTestEnvironment.withSecurityRulesDisabled()

Запустите функцию настройки теста с контекстом, который ведет себя так, как если бы правила безопасности были отключены.

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

RulesTestEnvironment.cleanup()

Этот метод уничтожает все RulesTestContexts созданные в тестовой среде, и очищает базовые ресурсы, обеспечивая чистый выход.

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

assertSucceeds(pr: Promise<any>)) => Promise<any>

Это служебная функция тестового примера.

Функция утверждает, что переданное обещание, обертывающее операцию эмулятора, будет разрешено без нарушений правил безопасности.

await assertSucceeds(setDoc(alice.firestore(), '/users/alice'), { ... });

assertFails(pr: Promise<any>)) => Promise<any>

Это служебная функция тестового примера.

Функция утверждает, что предоставленный промис, обертывающий операцию эмулятора, будет отклонен с нарушением правил безопасности.

await assertFails(setDoc(alice.firestore(), '/users/bob'), { ... });

Методы, специфичные для эмулятора

Также см. общие методы тестирования и служебные функции в v9 SDK .

RulesTestEnvironment.clearFirestore() => Promise<void>

Этот метод очищает данные в базе данных Firestore, принадлежащие projectId , настроенному для эмулятора Firestore.

RulesTestContext.firestore(settings?: Firestore.FirestoreSettings) => Firestore;

Этот метод получает экземпляр Firestore для этого тестового контекста. Возвращенный экземпляр Firebase JS Client SDK можно использовать с клиентскими API SDK (модульным или совместимым с v9).

Визуализация оценок правил

Эмулятор Cloud Firestore позволяет визуализировать запросы клиентов в пользовательском интерфейсе Emulator Suite, включая отслеживание оценки для правил безопасности Firebase.

Откройте вкладку Firestore > Requests , чтобы просмотреть подробную последовательность оценки для каждого запроса.

Монитор запросов эмулятора Firestore, показывающий оценки правил безопасности

Создание тестовых отчетов

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

Чтобы получить отчеты, запросите открытую конечную точку в эмуляторе во время его работы. Для удобной для браузера версии используйте следующий URL-адрес:

http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage.html

Это разбивает ваши правила на выражения и подвыражения, на которые вы можете навести указатель мыши для получения дополнительной информации, включая количество вычислений и возвращаемых значений. Чтобы получить необработанную версию этих данных в формате JSON, включите в запрос следующий URL-адрес:

http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage

Отличия эмулятора от продакшена

  1. Вам не нужно явно создавать проект Cloud Firestore. Эмулятор автоматически создает любой доступный экземпляр.
  2. Эмулятор Cloud Firestore не работает с обычным потоком аутентификации Firebase. Вместо этого в Firebase Test SDK мы предоставили метод initializeTestApp() в библиотеке rules-unit-testing , который принимает поле auth . Дескриптор Firebase, созданный с помощью этого метода, будет вести себя так, как если бы он успешно прошел аутентификацию как любой предоставленный вами объект. Если вы передадите null , он будет вести себя как пользователь, не прошедший проверку подлинности (например, правила auth != null не пройдут).

Устранение известных проблем

При использовании эмулятора Cloud Firestore вы можете столкнуться со следующими известными проблемами. Следуйте приведенным ниже инструкциям, чтобы устранить любое необычное поведение, с которым вы столкнулись. Эти заметки написаны с учетом библиотеки модульного тестирования правил безопасности, но общие подходы применимы к любому Firebase SDK.

Поведение теста непоследовательно

Если ваши тесты время от времени проходят и не проходят, даже без каких-либо изменений в самих тестах, вам может потребоваться убедиться, что они правильно упорядочиваются. Большинство взаимодействий с эмулятором являются асинхронными, поэтому дважды проверьте правильность последовательности всего асинхронного кода. Вы можете исправить последовательность, либо связав промисы в цепочку, либо свободно используя нотацию await .

В частности, просмотрите следующие асинхронные операции:

  • Установка правил безопасности, например, с помощью initializeTestEnvironment .
  • Чтение и запись данных, например, с db.collection("users").doc("alice").get() .
  • Операционные утверждения, включая assertSucceeds и assertFails .

Тесты проходят только при первой загрузке эмулятора

Эмулятор имеет состояние. Он хранит все записанные в него данные в памяти, поэтому любые данные теряются всякий раз, когда эмулятор выключается. Если вы запускаете несколько тестов для одного и того же идентификатора проекта, каждый тест может создавать данные, которые могут повлиять на последующие тесты. Вы можете использовать любой из следующих методов, чтобы обойти это поведение:

  • Используйте уникальные идентификаторы проекта для каждого теста. Обратите внимание, что если вы решите сделать это, вам нужно будет вызывать initializeTestEnvironment как часть каждого теста; правила автоматически загружаются только для идентификатора проекта по умолчанию.
  • Реструктурируйте свои тесты, чтобы они не взаимодействовали с ранее записанными данными (например, используйте разные коллекции для каждого теста).
  • Удалите все данные, записанные во время теста.

Настройка теста очень сложная

При настройке теста вы можете захотеть изменить данные таким образом, который на самом деле не разрешен вашими правилами безопасности Cloud Firestore. Если ваши правила усложняют настройку теста, попробуйте использовать RulesTestEnvironment.withSecurityRulesDisabled на этапах настройки, чтобы операции чтения и записи не вызывали ошибок PERMISSION_DENIED .

После этого ваш тест может выполнять операции как аутентифицированный или неаутентифицированный пользователь, используя RulesTestEnvironment.authenticatedContext и unauthenticatedContext соответственно. Это позволяет вам проверить, правильно ли ваши правила безопасности Cloud Firestore разрешают/запрещают различные случаи.