Como estruturar as regras de segurança do Cloud Firestore

Com as regras de segurança do Cloud Firestore, você pode controlar o acesso a documentos e coleções no seu 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 Cloud 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 Cloud Firestore evitando conflitos entre as regras de segurança do Cloud 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 Cloud Firestore no projeto. Atualmente, cada projeto tem apenas um único banco de dados chamado (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 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 se referir a um documento específico, como em match /cities/SF ou usar caracteres curingas para se referir a 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 são avaliadas, a variável city resolverá o nome do documento da cidade, como SF ou NYC.

Operações específicas

Em algumas situações, é melhor dividir read e write em operações mais específicas. 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. 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 Cloud 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 contenha uma subcoleção landmarks. As regras de segurança se aplicam apenas 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 executar o aninhamento de instruções match, o caminho da instrução match interna estará sempre relacionado 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

Para que as regras se apliquem a uma hierarquia arbitrariamente profunda, use a sintaxe de caracteres curinga recursivos, {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. 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, e não a um caminho vazio. Assim, match /cities/{city}/{document=**} corresponde a documentos em subcoleções, mas não na coleção de cities, enquanto match /cities/{document=**} corresponde a ambos os documentos na coleção e nas subcoleções de cities.

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, os caracteres curinga recursivos correspondem a zero ou mais itens de caminho. match/cities/{city}/{document=**} corresponde a documentos em todas as subcoleções e também a documentos na coleção de cities.

Para ativar essa versão, adicione rules_version = '2'; à parte superior 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, é preciso 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. Quando 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 será 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
  • 10 para solicitações de documento único e de consulta.
  • 20 para leituras de vários documentos, transações e gravações em lote. O limite anterior de 10 também se aplica a cada operação.

    Por exemplo, imagine que você crie uma solicitação de gravação em lote com três operações de gravação, e que suas regras de segurança usem duas chamadas de acesso a documentos para validar cada gravação. Nesse caso, cada gravação usa duas das 10 chamadas de acesso, e a solicitação de gravação em lote usa seis das 20 chamadas de acesso.

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.

Profundidade máxima da chamada da função 20
Número máximo de chamadas de função recorrentes ou cíclicas 0 &lpar;não permitido&rpar;
Número máximo de expressões avaliadas por solicitação 1.000
Tamanho máximo de um conjunto de regras 64 KB

Próximas etapas