Join us for Firebase Summit on November 10, 2021. Tune in to learn how Firebase can help you accelerate app development, release with confidence, and scale with ease. Register

Написание условий для правил безопасности Cloud Firestore

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

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

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

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

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 аутентификации или Google Cloud Platform удостоверений , то request.auth переменная содержит сведения о проверке подлинности для клиента , запрашивающего данные. Для получения дополнительной информации о request.auth см справочную документацию .

Проверка данных

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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