Ir para o console

Consultar dados de maneira segura

Com base nos conceitos de Como estruturar regras de segurança e Como escrever condições para regras de segurança, desenvolvemos esta página para explicar como as regras de segurança do Cloud Firestore interagem com as consultas. Vamos examinar em detalhes como as regras de segurança afetam as consultas que você pode escrever. Além disso, vamos saber como garantir que suas consultas usem as mesmas restrições que suas regras de segurança. Por último, também veremos como escrever regras de segurança para permitir ou negar consultas com base nas propriedades dela, como limit e orderBy.

Consultas e regras de segurança

Ao escrever consultas para recuperar documentos, lembre-se de que regras de segurança não são filtros. As consultas podem falhar ou serem bem-sucedidas. Para economizar tempo e recursos, o Cloud Firestore avalia uma consulta com relação ao potencial conjunto de resultados em vez dos valores de campo reais de todos os seus documentos. Se for possível que uma consulta retorne documentos para os quais o cliente não tem permissão de leitura, toda a solicitação falhará.

Como demonstrado nos exemplos abaixo, você precisa escrever consultas que atendam às restrições das suas regras de segurança.

Proteger e consultar documentos com base em auth.uid

O exemplo a seguir demonstra como escrever uma consulta para recuperar documentos protegidos por uma regra de segurança. Considere um banco de dados que contém uma coleção de documentos story:

/stories/{storyid}

{
  title: "A Great Story",
  content: "Once upon a time...",
  author: "some_auth_id",
  published: false
}

Além dos campos title e content, cada documento armazena os campos author e published para usar para controle de acesso. Após analisar os exemplos, é possível concluir que o aplicativo usa o Firebase Authentication para definir o campo author como o UID do usuário que criou o documento. O Firebase Authentication também preenche a variável request.auth nas regras de segurança.

A regra de segurança a seguir usa as variáveis request.auth e resource.data para restringir o acesso de leitura e gravação de cada story ao respectivo autor:

service cloud.firestore {
  match /databases/{database}/documents {
    match /stories/{storyid} {
      // Only the authenticated user who authored the document can read or write
      allow read, write: if request.auth.uid == resource.data.author;
    }
  }
}

Suponha que seu app inclua uma página que mostra ao usuário uma lista de documentos story de autoria própria. Você pode pensar que é possível usar a seguinte consulta para preencher esta página. No entanto, a consulta falhará, porque ela não inclui as mesmas restrições que suas regras de segurança:

Inválido: as restrições da consulta não correspondem às restrições das regras de segurança.

// This query will fail
db.collection("stories").get()

A consulta falhará mesmo se o usuário atual for realmente o autor de todos os documentos story. O motivo para esse comportamento é que, quando o Cloud Firestore aplica suas regras de segurança, ele avalia a consulta em relação ao conjunto de resultados potenciais dela, e não em relação às propriedades reais dos documentos no seu banco de dados. Se uma consulta puder potencialmente incluir documentos que violam as regras de segurança, ela falhará.

Em contraste, a seguinte consulta é bem-sucedida, porque inclui a mesma restrição no campo author que as regras de segurança:

Válido: as restrições da consulta correspondem às restrições das regras de segurança.

var user = firebase.auth().currentUser;

db.collection("stories").where("author", "==", user.uid).get()

Proteger e consultar documentos com base em um campo

Para demonstrar melhor a interação entre consultas e regras, as regras de segurança abaixo expandem o acesso de leitura para a coleção de stories para permitir que qualquer usuário leia documentos de story quando o campo published estiver definido como true.

service cloud.firestore {
  match /databases/{database}/documents {
    match /stories/{storyid} {
      // Anyone can read a published story; only story authors can read unpublished stories
      allow read: if resource.data.published == true || request.auth.uid == resource.data.author;
      // Only story authors can write
      allow write: if request.auth.uid == resource.data.author;
    }
  }
}

A consulta a páginas publicadas precisa incluir as mesmas restrições que as regras de segurança:

db.collection("stories").where("published", "==", true).get()

A restrição de consulta .where("published", "==", true) garante que resource.data.published seja true para qualquer resultado. Portanto, essa consulta satisfaz as regras de segurança e pode ler os dados.

Como avaliar restrições em consultas

Suas regras de segurança também podem aceitar ou negar consultas com base nas próprias restrições. A variável request.query contém as propriedades limit, offset e orderBy de uma consulta. Por exemplo, suas regras de segurança podem negar qualquer consulta que não limite o número máximo de documentos recuperados a um determinado intervalo:

allow list: if request.query.limit <= 10;

O conjunto de regras a seguir demonstra como escrever regras de segurança que avaliam restrições incluídas em consultas. Este exemplo expande o conjunto de regras stories anterior com as seguintes alterações:

  • O conjunto de regras separa a regra de leitura em regras get e list.
  • A regra get restringe a recuperação de documentos únicos para documentos públicos ou documentos de autoria do usuário.
  • A regra list aplica as mesmas restrições que get, mas para consultas. Ela também verifica o limite da consulta e nega qualquer consulta sem limite ou com um limite superior a 10.
  • O conjunto de regras define uma função authorOrPublished() para evitar a duplicação de código.
service cloud.firestore {

  match /databases/{database}/documents {

    match /stories/{storyid} {

      // Returns `true` if the requested story is 'published'
      // or the user authored the story
      function authorOrPublished() {
        return resource.data.published == true || request.auth.uid == resource.data.author;
      }

      // Deny any query not limited to 10 or fewer documents
      // Anyone can query published stories
      // Authors can query their unpublished stories
      allow list: if request.query.limit <= 10 &&
                     authorOrPublished();

      // Anyone can retrieve a published story
      // Only a story's author can retrieve an unpublished story
      allow get: if authorOrPublished();

      // Only a story's authors can write to a story
      allow write: if request.auth.uid == resource.data.author;
    }

  }
}

Próximas etapas