Структурирование правил безопасности Cloud Firestore

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

В этом руководстве описывается основной синтаксис и структура правил безопасности. Объедините этот синтаксис с условиями правил безопасности, чтобы создать полные наборы правил.

Объявление службы и базы данных

Правила безопасности Cloud Firestore всегда начинаются со следующего объявления:

service cloud.firestore {
  match /databases/{database}/documents {
    // ...
  }
}

service cloud.firestore распространяет правила на Cloud Firestore, предотвращая конфликты между правилами безопасности Cloud Firestore и правилами для других продуктов, таких как Cloud Storage.

Объявление match /databases/{database}/documents указывает, что правила должны соответствовать любой базе данных Cloud Firestore в проекте. В настоящее время каждый проект имеет только одну базу данных с именем (default) .

Основные правила чтения/записи

Базовые правила состоят из оператора match , указывающего путь к документу, и allow выражения, позволяющего детализировать при чтении указанных данных:

service cloud.firestore {
  match /databases/{database}/documents {

    // Match any document in the 'cities' collection
    match /cities/{city} {
      allow read: if <condition>;
      allow write: if <condition>;
    }
  }
}

Все операторы сопоставления должны указывать на документы, а не на коллекции. Оператор match может указывать на конкретный документ, как в match /cities/SF , или использовать подстановочные знаки для указания на любой документ по указанному пути, как в match /cities/{city} .

В приведенном выше примере оператор match использует синтаксис подстановочного знака {city} . Это означает, что правило применяется к любому документу в коллекции cities , например /cities/SF или /cities/NYC . Когда выражения allow в операторе соответствия оцениваются, переменная city преобразуется в имя документа города, например SF или NYC .

Детальные операции

В некоторых ситуациях полезно разбить read и write на более детальные операции. Например, ваше приложение может захотеть применить другие условия для создания документа, чем для удаления документа. Или вы можете разрешить чтение отдельных документов, но запретить большие запросы.

Правило read можно разбить на get и list , а правило write можно разбить на create , update и delete :

service cloud.firestore {
  match /databases/{database}/documents {
    // A read rule can be divided into get and list rules
    match /cities/{city} {
      // Applies to single document read requests
      allow get: if <condition>;

      // Applies to queries and collection read requests
      allow list: if <condition>;
    }

    // A write rule can be divided into create, update, and delete rules
    match /cities/{city} {
      // Applies to writes to nonexistent documents
      allow create: if <condition>;

      // Applies to writes to existing documents
      allow update: if <condition>;

      // Applies to delete operations
      allow delete: if <condition>;
    }
  }
}

Иерархические данные

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

Рассмотрим ситуацию, когда каждый документ в коллекции cities содержит подколлекцию landmarks . Правила безопасности применяются только к совпадающему пути, поэтому элементы управления доступом, определенные для коллекции cities , не применяются к подколлекции landmarks . Вместо этого напишите явные правила для управления доступом к подколлекциям:

service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city} {
      allow read, write: if <condition>;

        // Explicitly define rules for the 'landmarks' subcollection
        match /landmarks/{landmark} {
          allow read, write: if <condition>;
        }
    }
  }
}

При вложении операторов match путь внутреннего оператора match всегда относится к пути внешнего оператора match . Таким образом, следующие наборы правил эквивалентны:

service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city} {
      match /landmarks/{landmark} {
        allow read, write: if <condition>;
      }
    }
  }
}
service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city}/landmarks/{landmark} {
      allow read, write: if <condition>;
    }
  }
}

Рекурсивные подстановочные знаки

Если вы хотите, чтобы правила применялись к произвольно глубокой иерархии, используйте синтаксис рекурсивных подстановочных знаков {name=**} . Например:

service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the cities collection as well as any document
    // in a subcollection.
    match /cities/{document=**} {
      allow read, write: if <condition>;
    }
  }
}

При использовании рекурсивного синтаксиса подстановочных знаков переменная подстановочных знаков будет содержать весь соответствующий сегмент пути, даже если документ находится в глубоко вложенной подколлекции. Например, перечисленные выше правила будут соответствовать документу, расположенному в /cities/SF/landmarks/coit_tower , а значение переменной document будет SF/landmarks/coit_tower .

Обратите внимание, однако, что поведение рекурсивных подстановочных знаков зависит от версии правил.

Версия 1

Правила безопасности используют версию 1 по умолчанию. В версии 1 рекурсивные подстановочные знаки соответствуют одному или нескольким элементам пути. Они не соответствуют пустому пути, поэтому match /cities/{city}/{document=**} соответствует документам в подколлекциях, но не в коллекции cities , тогда как match /cities/{document=**} соответствует обоим документам в коллекции. коллекции и подколлекции cities .

Рекурсивные подстановочные знаки должны стоять в конце оператора соответствия.

Версия 2

В версии 2 правил безопасности рекурсивные подстановочные знаки соответствуют нулю или более элементам пути. match/cities/{city}/{document=**} соответствует документам в любых вложенных коллекциях, а также документам в коллекции cities .

Вы должны подписаться на версию 2, добавив rules_version = '2'; в верхней части ваших правил безопасности:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the cities collection as well as any document
    // in a subcollection.
    match /cities/{city}/{document=**} {
      allow read, write: if <condition>;
    }
  }
}

У вас может быть не более одного рекурсивного подстановочного знака на оператор соответствия, но в версии 2 вы можете разместить этот подстановочный знак в любом месте оператора соответствия. Например:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the songs collection group
    match /{path=**}/songs/{song} {
      allow read, write: if <condition>;
    }
  }
}

Если вы используете запросы группы сбора , вы должны использовать версию 2, см. раздел Защита запросов группы сбора .

Перекрывающиеся операторы соответствия

Документ может соответствовать более чем одному оператору match . В true , когда запросу соответствует несколько allow выражений, доступ разрешается, если выполняется любое из условий:

service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the 'cities' collection.
    match /cities/{city} {
      allow read, write: if false;
    }

    // Matches any document in the 'cities' collection or subcollections.
    match /cities/{document=**} {
      allow read, write: if true;
    }
  }
}

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

Ограничения правил безопасности

При работе с правилами безопасности обратите внимание на следующие ограничения:

Ограничение Подробности
Максимальное количество вызовов exists() , get() и getAfter() на запрос
  • 10 для запросов отдельных документов и запросов запросов.
  • 20 для чтения нескольких документов, транзакций и пакетной записи. Предыдущее ограничение в 10 также применяется к каждой операции.

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

Превышение любого ограничения приводит к ошибке отказа в разрешении.

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

Максимальная глубина вложенного оператора match 10
Максимальная длина пути в сегментах пути, допустимая в наборе вложенных операторов match . 100
Максимальное количество переменных захвата пути, разрешенное в наборе вложенных операторов match 20
Максимальная глубина вызова функции 20
Максимальное количество аргументов функции 7
Максимальное количество привязок переменной let на функцию 10
Максимальное количество рекурсивных или циклических вызовов функций 0 (не разрешено)
Максимальное количество выражений, оцениваемых на запрос 1000
Максимальный размер набора правил Наборы правил должны соответствовать двум ограничениям размера:
  • ограничение в 256 КБ на размер исходного текста набора правил, опубликованного из консоли Firebase или из интерфейса командной строки с помощью firebase deploy .
  • ограничение в 250 КБ на размер скомпилированного набора правил, которое возникает, когда Firebase обрабатывает исходный код и делает его активным на серверной части.

Следующие шаги