Estruturar regras de segurança
Com as regras de segurança do Firestore, é possível controlar o acesso a documentos e coleções no banco de dados. Usando a sintaxe de regras flexíveis, você pode criar regras que correspondem a várias operações, de todas as gravações em todo o banco de dados até operações em um documento específico.
Veja neste guia a sintaxe básica e a estrutura das regras de segurança. Use esta sintaxe com as condições de regras de segurança para criar conjuntos de regras completos.
Declaração de serviço e banco de dados
As regras de segurança do Firestore sempre começam com a seguinte declaração:
service cloud.firestore {
match /databases/{database}/documents {
// ...
}
}
A declaração service cloud.firestore
define o escopo das regras do
Firestore, evitando assim conflitos entre as regras de segurança do Firestore e as
regras de outros produtos, como o Cloud Storage.
A declaração match /databases/{database}/documents
especifica que as regras devem
corresponder a qualquer banco de dados do Firestore no projeto. Atualmente, cada projeto tem apenas um banco de dados nomeado (default)
.
Regras básicas de leitura e gravação
As regras básicas consistem em uma instrução match
que especifica um caminho de documento e uma expressão allow
que, por sua vez, detalha quando a leitura dos dados especificados é permitida:
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>;
}
}
}
Todas as instruções de correspondência devem se referir a documentos e não coleções. Uma instrução de correspondência pode indicar um documento específico, como em match /cities/SF
, ou usar caracteres curingas para indicar qualquer documento no caminho especificado, como em match /cities/{city}
.
No exemplo acima, a instrução de correspondência usa a sintaxe com caractere curinga {city}
.
Isso significa que a regra se aplica a qualquer documento na coleção cities
, como
/cities/SF
ou /cities/NYC
. Quando as expressões allow
na instrução de correspondência forem
avaliadas, a variável city
resultará no nome do documento da cidade,
como SF
ou NYC
.
Operações específicas
Em algumas situações, é útil dividir read
e write
em operações mais granulares. Por exemplo, você pode aplicar condições diferentes para a criação e a exclusão de documentos no seu app. Se preferir, permita leituras de documentos únicos, mas negue grandes consultas.
Uma regra read
pode ser dividida em get
e list
, enquanto uma regra write
pode ser dividida em create
, update
e 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>;
}
}
}
Dados hierárquicos
Os dados no Firestore são organizados em coleções de documentos, e cada documento pode estender a hierarquia por meio de subcoleções. É importante entender como as regras de segurança interagem com dados hierárquicos.
Considere a situação em que cada documento na coleção cities
contém uma
subcoleção landmarks
. As regras de segurança se aplicam somente ao caminho correspondente, de modo que
os controles de acesso definidos na coleção cities
não se aplicam à
subcoleção landmarks
. Em vez disso, escreva regras explícitas para controlar o acesso
a subcoleções:
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>;
}
}
}
}
Ao aninhar instruções match
, o caminho da instrução match
interna é sempre
relativo ao caminho da instrução match
externa. Os seguintes conjuntos de regras
são equivalentes:
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>;
}
}
}
Caracteres curinga recursivos
Se você quer aplicar regras a uma hierarquia arbitrariamente profunda, use a sintaxe de caractere curinga recorrente, {name=**}
. Exemplo:
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>;
}
}
}
Ao usar a sintaxe com caractere curinga recorrente, a variável dele terá todo o segmento do caminho de correspondência, mesmo que o documento esteja localizado em uma subcoleção aninhada em vários níveis. Por exemplo, as regras listadas acima corresponderiam
a um documento localizado em /cities/SF/landmarks/coit_tower
, e o valor
da variável document
seria SF/landmarks/coit_tower
.
No entanto, o comportamento de caracteres curinga recursivos depende da versão das regras.
Versão 1
As regras de segurança usam a versão 1 por padrão. Nela, os caracteres curinga recursivos
correspondem a um ou mais itens de caminho. Eles não correspondem a um caminho vazio, por isso
match /cities/{city}/{document=**}
corresponde aos documentos em subcoleções, mas
não na coleção cities
, enquanto match /cities/{document=**}
corresponde
a ambos os documentos na coleção cities
e nas subcoleções.
Os caracteres curinga recursivos precisam aparecer no fim de uma instrução de correspondência.
Versão 2
Na versão 2 das regras de segurança, caracteres curingas recorrentes correspondem a zero ou mais itens
de caminho. match/cities/{city}/{document=**}
corresponde a documentos em todas as
subcoleções, bem como aos documentos na coleção cities
.
Você deve ativar a versão 2 adicionando rules_version = '2';
na parte de cima das
suas regras de segurança:
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>;
}
}
}
É permitido ter no máximo um caractere curinga recursivo por instrução de correspondência. No entanto, na versão 2, é possível posicioná-lo em qualquer lugar da instrução. Exemplo:
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>;
}
}
}
Se você usar consultas do grupo de coleções, será necessário utilizar a versão 2. Consulte Como proteger as consultas do grupo de coleções.
Sobreposição de instruções de correspondência
É possível que um documento corresponda a mais de uma instrução match
. No caso de
várias expressões allow
corresponderem a uma solicitação, o acesso será permitido
se qualquer uma das condições for true
:
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;
}
}
}
No exemplo acima, todas as leituras e gravações da coleção cities
serão
permitidas porque a segunda regra é sempre true
, mesmo que a primeira
regra seja sempre false
.
Limites da regra de segurança
Ao trabalhar com regras de segurança, observe os seguintes limites:
Limite | Detalhes |
---|---|
Número máximo de chamadas exists() , get() e getAfter() por solicitação. |
Ao exceder qualquer um desses limites, ocorrerá um erro de permissão negada. Algumas chamadas de acesso a documentos podem ser armazenadas em cache. Elas não entram na conta dos limites. |
Máxima profundidade da instrução match aninhada |
10 |
Tamanho do caminho máximo, em segmentos de caminho, permitido em um grupo de instruções
match aninhadas |
100 |
Número máximo de variáveis de captura de caminho permitidas em um conjunto de
instruções match aninhadas |
20 |
Profundidade máxima da chamada da função | 20 |
Número máximo de argumentos de função | 7 |
Número máximo de vinculações de variáveis let por função |
10 |
Número máximo de chamadas de função recorrentes ou cíclicas | 0 (não permitido) |
Número máximo de expressões avaliadas por solicitação | 1.000 |
Tamanho máximo de um conjunto de regras | Os conjuntos de regras precisam atender a dois limites de tamanho:
|