Estruture as regras de segurança
As regras de segurança do Firestore permitem-lhe controlar o acesso a documentos e coleções na sua base de dados. A sintaxe de regras flexíveis permite-lhe criar regras que correspondem a qualquer coisa, desde todas as escritas na base de dados inteira até operações num documento específico.
Este guia descreve a sintaxe e a estrutura básicas das regras de segurança. Combine esta sintaxe com condições das regras de segurança para criar conjuntos de regras completos.
Declaração de serviço e base de dados
As regras de segurança do Firestore começam sempre com a seguinte declaração:
service cloud.firestore {
// The {database} wildcard allows the rules to reference any database,
// but these rules are only active on databases where they are explicitly deployed.
match /databases/{database}/documents {
// ...
}
}
A declaração service cloud.firestore
limita o âmbito das regras ao Firestore, o que evita 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 base de dados do Firestore no projeto. Embora um projeto possa conter até 100 bases de dados, apenas a primeira base de dados criada é designada como predefinição.
As regras de segurança do Firestore são aplicadas separadamente a cada base de dados com nome no seu projeto. Isto significa que, se criar várias bases de dados, tem de gerir e implementar regras para cada uma individualmente. Para ver instruções detalhadas sobre a implementação das atualizações, consulte o artigo Implemente as suas atualizações.
Regras básicas de leitura/escrita
As regras básicas consistem numa declaração match
que especifica um caminho do documento e numa expressão allow
que 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 declarações de correspondência devem apontar para documentos e não para coleções. Uma declaração de correspondência pode apontar para um documento específico, como em match /cities/SF
, ou usar carateres universais para apontar para qualquer documento no caminho especificado, como em match /cities/{city}
.
No exemplo acima, a declaração de correspondência usa a sintaxe de caráter universal {city}
.
Isto 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 declaração de correspondência são avaliadas, a variável city
é resolvida para o nome do documento da cidade, como SF
ou NYC
.
Operações detalhadas
Em algumas situações, é útil dividir read
e write
em operações mais detalhadas. Por exemplo, a sua app pode querer aplicar condições diferentes à criação de documentos do que à eliminação de documentos. Em alternativa, pode querer
permitir leituras de documentos únicos, mas recusar consultas grandes.
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 estão organizados em coleções de documentos e cada documento pode expandir a hierarquia através de subcoleções. É importante compreender como as regras de segurança interagem com os 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 aplicam-se apenas ao caminho correspondente, pelo que os controlos de acesso definidos na coleção cities
não se aplicam à subcoleção landmarks
. Em alternativa, 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>;
}
}
}
}
Quando aninham declarações match
, o caminho da declaração match
interior é sempre relativo ao caminho da declaração match
exterior. Por isso, 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>;
}
}
}
Carateres universais recursivos
Se quiser que as regras se apliquem a uma hierarquia arbitrariamente profunda, use a sintaxe de caráter universal recursivo, {name=**}
. Por 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>;
}
}
}
Quando usa a sintaxe de caráter universal recursivo, a variável de caráter universal contém o segmento do caminho correspondente completo, mesmo que o documento esteja localizado numa subcoleção profundamente aninhada. Por exemplo, as regras indicadas 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, tenha em atenção que o comportamento dos carateres universais recursivos depende da versão das regras.
Versão 1
As regras de segurança usam a versão 1 por predefinição. Na versão 1, os carateres universais recursivos correspondem a um ou mais itens de caminho. Não correspondem a um caminho vazio, pelo que match /cities/{city}/{document=**}
corresponde a documentos em subcoleções, mas não na coleção cities
, enquanto match /cities/{document=**}
corresponde a documentos na coleção cities
e nas subcoleções.
Os carateres universais recursivos têm de aparecer no final de uma declaração de correspondência.
Versão 2
Na versão 2 das regras de segurança, os carateres universais recursivos correspondem a zero ou mais itens do caminho. match/cities/{city}/{document=**}
corresponde a documentos em quaisquer subcoleções, bem como a documentos na coleção cities
.
Tem de aderir à versão 2 adicionando rules_version = '2';
na parte superior das 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>;
}
}
}
Pode ter, no máximo, um caráter universal recursivo por declaração de correspondência, mas na versão 2, pode colocar este caráter universal em qualquer parte da declaração de correspondência. Por 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 usar consultas de grupos de recolha, tem de usar a versão 2. Consulte o artigo sobre como proteger consultas de grupos de recolha.
Declarações de correspondência sobrepostas
É possível que um documento corresponda a mais do que uma declaração match
. No caso em que várias expressões allow
correspondem a um pedido, o acesso é 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 escritas na coleção cities
são permitidas porque a segunda regra é sempre true
, mesmo que a primeira regra seja sempre false
.
Limites das regras de segurança
Quando trabalhar com regras de segurança, tenha em atenção os seguintes limites:
Limite | Detalhes |
---|---|
Número máximo de chamadas exists() , get() e getAfter() por pedido |
Se exceder qualquer um dos limites, recebe um erro de acesso negado. Algumas chamadas de acesso a documentos podem ser colocadas em cache e as chamadas em cache não contam para os limites. |
Profundidade máxima da declaração match aninhada |
10 |
Comprimento máximo do caminho, em segmentos do caminho, permitido num conjunto de declarações aninhadas
match |
100 |
Número máximo de variáveis de captura de caminho permitidas num conjunto de
declarações match aninhadas |
20 |
Profundidade máxima de chamadas de funções | 20 |
Número máximo de argumentos de funções | 7 |
Número máximo de associações de variáveis let por função |
10 |
Número máximo de chamadas de funções recursivas ou cíclicas | 0 (não permitido) |
Número máximo de expressões avaliadas por pedido | 1000 |
Tamanho máximo de um conjunto de regras | Os conjuntos de regras têm de obedecer a dois limites de tamanho:
|
Passos seguintes
- Escrever condições de regras de segurança personalizadas.
- Leia a referência das regras de segurança.