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

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

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

В течение нескольких основных тестовых случаев с простыми правилами, попробовать образец QuickStart .

Общие сведения о правилах безопасности Cloud Firestore

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

Правила безопасности Cloud Firestore состоят из двух частей:

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

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

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

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

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

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

firebase setup:emulators:firestore

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

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

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 SDKs работы с эмуляторами непосредственно, только @firebase/rules-unit-testing библиотеки поддерживает насмешливую auth в правилах безопасности, делая модульные тесты гораздо проще. Кроме того, библиотека поддерживает несколько специфичных для эмулятора функций, таких как очистка всех данных, как указано ниже.
  • Эмуляторы также будут принимать производственные токены Firebase Auth, предоставляемые через клиентские SDK, и соответственно оценивать правила, что позволяет напрямую подключать ваше приложение к эмуляторам при интеграции и ручных тестах.

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

Запускать локальные модульные тесты с помощью SDK JavaScript v9

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

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

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

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

Вы импортируете библиотеку с помощью модульных операторов импорта 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 или совместимость с v9).

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

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

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

Монитор запросов эмулятора 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 разрешают / отклоняют различные случаи.