Idioma das regras de segurança

As regras de segurança do Firebase utilizam linguagens flexíveis, poderosas e personalizadas que oferecem suporte a uma ampla gama de complexidade e granularidade. Você pode tornar suas regras tão específicas ou gerais quanto fizer sentido para seu aplicativo. As regras do Realtime Database usam uma sintaxe semelhante a JavaScript em uma estrutura JSON. As regras do Cloud Firestore e do Cloud Storage usam uma linguagem baseada na Common Expression Language (CEL) , que se baseia no CEL com instruções match e allow que oferecem suporte ao acesso concedido condicionalmente.

Porém, como essas linguagens são personalizadas, há uma curva de aprendizado. Use este guia para entender melhor a linguagem das regras à medida que você se aprofunda em regras mais complexas.

Selecione um produto para saber mais sobre suas regras.

Estrutura básica

Cloud Firestore

As regras de segurança do Firebase no Cloud Firestore e no Cloud Storage usam a seguinte estrutura e sintaxe:

service <<name>> {
  // Match the resource path.
  match <<path>> {
    // Allow the request if the following conditions are true.
    allow <<methods>> : if <<condition>>
  }
}

É importante entender os seguintes conceitos-chave à medida que você cria as regras:

  • Solicitação: o método ou métodos invocados na instrução allow . Esses são métodos que você está permitindo executar. Os métodos padrão são: get , list , create , update e delete . Os métodos convenientes de read e write permitem amplo acesso de leitura e gravação no banco de dados ou caminho de armazenamento especificado.
  • Caminho: O banco de dados ou local de armazenamento, representado como um caminho URI.
  • Regra: A instrução allow , que inclui uma condição que permite uma solicitação se for avaliada como verdadeira.

Cada um desses conceitos é descrito com mais detalhes abaixo.

Armazenamento na núvem

As regras de segurança do Firebase no Cloud Firestore e no Cloud Storage usam a seguinte estrutura e sintaxe:

service <<name>> {
  // Match the resource path.
  match <<path>> {
    // Allow the request if the following conditions are true.
    allow <<methods>> : if <<condition>>
  }
}

É importante entender os seguintes conceitos-chave à medida que você cria as regras:

  • Solicitação: o método ou métodos invocados na instrução allow . Esses são métodos que você está permitindo executar. Os métodos padrão são: get , list , create , update e delete . Os métodos convenientes de read e write permitem amplo acesso de leitura e gravação no banco de dados ou caminho de armazenamento especificado.
  • Caminho: O banco de dados ou local de armazenamento, representado como um caminho URI.
  • Regra: A instrução allow , que inclui uma condição que permite uma solicitação se for avaliada como verdadeira.

Cada um desses conceitos é descrito com mais detalhes abaixo.

Banco de dados em tempo real

No Realtime Database, as regras de segurança do Firebase consistem em expressões semelhantes a JavaScript contidas em um documento JSON.

Eles usam a seguinte sintaxe:

{
  "rules": {
    "<<path>>": {
    // Allow the request if the condition for each method is true.
      ".read": <<condition>>,
      ".write": <<condition>>,
      ".validate": <<condition>>
    }
  }
}

Existem três elementos básicos na regra:

  • Caminho: o local do banco de dados. Isso reflete a estrutura JSON do seu banco de dados.
  • Solicitação: estes são os métodos que a regra usa para conceder acesso. As regras read e write concedem amplo acesso de leitura e gravação, enquanto as regras validate atuam como uma verificação secundária para conceder acesso com base em dados recebidos ou existentes.
  • Condição: A condição que permite uma solicitação se for avaliada como verdadeira.

Construções de regras

Cloud Firestore

Os elementos básicos de uma regra no Cloud Firestore e no Cloud Storage são os seguintes:

  • A declaração service : declara o produto Firebase ao qual as regras se aplicam.
  • O bloco match : define um caminho no banco de dados ou bucket de armazenamento ao qual as regras se aplicam.
  • A instrução allow : Fornece condições para concessão de acesso, diferenciadas por métodos. Os métodos suportados incluem: get , list , create , update , delete e os métodos convenientes read e write .
  • Declarações function opcionais: fornecem a capacidade de combinar e agrupar condições para uso em diversas regras.

O service contém um ou mais blocos match com instruções allow que fornecem condições que concedem acesso às solicitações. As variáveis request e resource estão disponíveis para uso em condições de regra. A linguagem das regras de segurança do Firebase também oferece suporte a declarações function .

Versão de sintaxe

A instrução syntax indica a versão da linguagem Firebase Rules usada para escrever a fonte. A versão mais recente da linguagem é v2 .

rules_version = '2';
service cloud.firestore {
...
}

Se nenhuma instrução rules_version for fornecida, suas regras serão avaliadas usando o mecanismo v1 .

Serviço

A declaração de service define a qual produto ou serviço do Firebase suas regras se aplicam. Você só pode incluir uma declaração service por arquivo de origem.

Cloud Firestore

service cloud.firestore {
 // Your 'match' blocks with their corresponding 'allow' statements and
 // optional 'function' declarations are contained here
}

Armazenamento na núvem

service firebase.storage {
  // Your 'match' blocks with their corresponding 'allow' statements and
  // optional 'function' declarations are contained here
}

Se você estiver definindo regras para o Cloud Firestore e o Cloud Storage usando a CLI do Firebase, será necessário mantê-las em arquivos separados.

Corresponder

Um bloco match declara um padrão path que corresponde ao caminho da operação solicitada (o request.path recebido). O corpo da match deve ter um ou mais blocos match aninhados, instruções allow ou declarações function . O caminho nos blocos match aninhados é relativo ao caminho no bloco match pai.

O padrão path é um nome semelhante a um diretório que pode incluir variáveis ​​ou curingas. O padrão path permite correspondências de segmento de caminho único e segmento de caminho múltiplo. Quaisquer variáveis ​​vinculadas a um path são visíveis no escopo match ou em qualquer escopo aninhado onde o path é declarado.

As correspondências com um padrão path podem ser parciais ou completas:

  • Correspondências parciais: o padrão path é uma correspondência de prefixo de request.path .
  • Correspondências completas: o padrão path corresponde a todo request.path .

Quando uma correspondência completa é feita, as regras dentro do bloco são avaliadas. Quando uma correspondência parcial é feita, as regras match aninhada são testadas para verificar se algum path aninhado completará a correspondência.

As regras em cada match completa são avaliadas para determinar se a solicitação deve ser permitida. Se alguma regra correspondente conceder acesso, a solicitação será permitida. Se nenhuma regra correspondente conceder acesso, a solicitação será negada.

// Given request.path == /example/hello/nested/path the following
// declarations indicate whether they are a partial or complete match and
// the value of any variables visible within the scope.
service firebase.storage {
  // Partial match.
  match /example/{singleSegment} {   // `singleSegment` == 'hello'
    allow write;                     // Write rule not evaluated.
    // Complete match.
    match /nested/path {             // `singleSegment` visible in scope.
      allow read;                    // Read rule is evaluated.
    }
  }
  // Complete match.
  match /example/{multiSegment=**} { // `multiSegment` == /hello/nested/path
    allow read;                      // Read rule is evaluated.
  }
}

Como mostra o exemplo acima, as declarações path suportam as seguintes variáveis:

  • Curinga de segmento único: uma variável curinga é declarada em um caminho envolvendo uma variável entre chaves: {variable} . Esta variável pode ser acessada na instrução match como uma string .
  • Curinga recursivo: o curinga recursivo ou de vários segmentos corresponde a vários segmentos de caminho em ou abaixo de um caminho. Este curinga corresponde a todos os caminhos abaixo do local definido. Você pode declará-lo adicionando a string =** no final da sua variável de segmento: {variable=**} . Esta variável pode ser acessada na instrução match como um objeto path .

Permitir

O bloco match contém uma ou mais instruções allow . Estas são suas regras reais. Você pode aplicar regras allow a um ou mais métodos. As condições em uma instrução allow devem ser avaliadas como verdadeiras para que o Cloud Firestore ou o Cloud Storage concedam qualquer solicitação recebida. Você também pode escrever instruções allow sem condições, por exemplo, allow read . Entretanto, se a instrução allow não incluir uma condição, ela sempre permitirá a solicitação desse método.

Se alguma das regras allow do método for satisfeita, a solicitação será permitida. Além disso, se uma regra mais ampla conceder acesso, as Regras concederão acesso e ignorarão quaisquer regras mais granulares que possam limitar o acesso.

Considere o exemplo a seguir, onde qualquer usuário pode ler ou excluir qualquer um de seus próprios arquivos. Uma regra mais granular só permite gravações se o usuário que solicita a gravação for proprietário do arquivo e o arquivo for um PNG. Um usuário pode excluir qualquer arquivo no subcaminho — mesmo que não sejam PNGs — porque a regra anterior permite isso.

service firebase.storage {
  // Allow the requestor to read or delete any resource on a path under the
  // user directory.
  match /users/{userId}/{anyUserFile=**} {
    allow read, delete: if request.auth != null && request.auth.uid == userId;
  }

  // Allow the requestor to create or update their own images.
  // When 'request.method' == 'delete' this rule and the one matching
  // any path under the user directory would both match and the `delete`
  // would be permitted.

  match /users/{userId}/images/{imageId} {
    // Whether to permit the request depends on the logical OR of all
    // matched rules. This means that even if this rule did not explicitly
    // allow the 'delete' the earlier rule would have.
    allow write: if request.auth != null && request.auth.uid == userId && imageId.matches('*.png');
  }
}

Método

Cada instrução allow inclui um método que concede acesso para solicitações recebidas do mesmo método.

Método Tipo de solicitação
Métodos de conveniência
read Qualquer tipo de solicitação de leitura
write Qualquer tipo de solicitação de gravação
Métodos padrão
get Leia solicitações para documentos ou arquivos únicos
list Ler solicitações de consultas e coleções
create Escreva novos documentos ou arquivos
update Grave em documentos de banco de dados existentes ou atualize metadados de arquivos
delete Excluir dados

Você não pode sobrepor métodos de leitura no mesmo bloco match ou métodos de gravação conflitantes na mesma declaração path .

Por exemplo, as seguintes regras falhariam:

service bad.example {
  match /rules/with/overlapping/methods {
    // This rule allows reads to all authenticated users
    allow read: if request.auth != null;

    match another/subpath {
      // This secondary, more specific read rule causes an error
      allow get: if request.auth != null && request.auth.uid == "me";
      // Overlapping write methods in the same path cause an error as well
      allow write: if request.auth != null;
      allow create: if request.auth != null && request.auth.uid == "me";
    }
  }
}

Função

À medida que suas regras de segurança se tornam mais complexas, você pode querer agrupar conjuntos de condições em funções que podem ser reutilizadas em seu conjunto de regras. As regras de segurança suportam funções personalizadas. A sintaxe para funções personalizadas é um pouco parecida com JavaScript, mas as funções de regras de segurança são escritas em uma linguagem específica de domínio que tem algumas limitações importantes:

  • As funções podem conter apenas uma única instrução return . Eles não podem conter nenhuma lógica adicional. Por exemplo, eles não podem executar loops ou chamar serviços externos.
  • As funções podem acessar automaticamente funções e variáveis ​​do escopo em que estão definidas. Por exemplo, uma função definida no escopo service cloud.firestore tem acesso à variável resource e funções integradas, como get() e exists() .
  • As funções podem chamar outras funções, mas não podem recorrer. A profundidade total da pilha de chamadas é limitada a 20.
  • Na versão de regras v2 , as funções podem definir variáveis ​​usando a palavra-chave let . As funções podem ter até 10 ligações let, mas devem terminar com uma instrução return.

Uma função é definida com a palavra-chave function e aceita zero ou mais argumentos. Por exemplo, você pode querer combinar os dois tipos de condições usadas nos exemplos acima em uma única função:

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

Aqui está um exemplo mostrando argumentos de função e atribuições let. Deixe que as instruções de atribuição sejam separadas por ponto e vírgula.

function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  let isAdmin = exists(/databases/$(database)/documents/admins/$(userId));
  return isAuthor || isAdmin;
}

Observe como a atribuição isAdmin impõe uma pesquisa na coleção admins. Para avaliação lenta sem exigir pesquisas desnecessárias, aproveite a natureza de curto-circuito de && (AND) e || (OR) comparações para chamar uma segunda função somente se isAuthor for mostrado como verdadeiro (para comparações && ) ou falso (para comparações || ).

function isAdmin(userId) {
  return exists(/databases/$(database)/documents/admins/$(userId));
}
function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  // `||` is short-circuiting; isAdmin called only if isAuthor == false.
  return isAuthor || isAdmin(userId);
}

O uso de funções em suas regras de segurança torna-as mais fáceis de manter à medida que a complexidade de suas regras aumenta.

Armazenamento na núvem

Os elementos básicos de uma regra no Cloud Firestore e no Cloud Storage são os seguintes:

  • A declaração service : declara o produto Firebase ao qual as regras se aplicam.
  • O bloco match : define um caminho no banco de dados ou bucket de armazenamento ao qual as regras se aplicam.
  • A instrução allow : Fornece condições para concessão de acesso, diferenciadas por métodos. Os métodos suportados incluem: get , list , create , update , delete e os métodos convenientes read e write .
  • Declarações function opcionais: fornecem a capacidade de combinar e agrupar condições para uso em diversas regras.

O service contém um ou mais blocos match com instruções allow que fornecem condições que concedem acesso às solicitações. As variáveis request e resource estão disponíveis para uso em condições de regra. A linguagem das regras de segurança do Firebase também oferece suporte a declarações function .

Versão de sintaxe

A instrução syntax indica a versão da linguagem Firebase Rules usada para escrever a fonte. A versão mais recente da linguagem é v2 .

rules_version = '2';
service cloud.firestore {
...
}

Se nenhuma instrução rules_version for fornecida, suas regras serão avaliadas usando o mecanismo v1 .

Serviço

A declaração de service define a qual produto ou serviço do Firebase suas regras se aplicam. Você só pode incluir uma declaração service por arquivo de origem.

Cloud Firestore

service cloud.firestore {
 // Your 'match' blocks with their corresponding 'allow' statements and
 // optional 'function' declarations are contained here
}

Armazenamento na núvem

service firebase.storage {
  // Your 'match' blocks with their corresponding 'allow' statements and
  // optional 'function' declarations are contained here
}

Se você estiver definindo regras para o Cloud Firestore e o Cloud Storage usando a CLI do Firebase, será necessário mantê-las em arquivos separados.

Corresponder

Um bloco match declara um padrão path que corresponde ao caminho da operação solicitada (o request.path recebido). O corpo da match deve ter um ou mais blocos match aninhados, instruções allow ou declarações function . O caminho nos blocos match aninhados é relativo ao caminho no bloco match pai.

O padrão path é um nome semelhante a um diretório que pode incluir variáveis ​​ou curingas. O padrão path permite correspondências de segmento de caminho único e segmento de caminho múltiplo. Quaisquer variáveis ​​vinculadas a um path são visíveis no escopo match ou em qualquer escopo aninhado onde o path é declarado.

As correspondências com um padrão path podem ser parciais ou completas:

  • Correspondências parciais: o padrão path é uma correspondência de prefixo de request.path .
  • Correspondências completas: o padrão path corresponde a todo request.path .

Quando uma correspondência completa é feita, as regras dentro do bloco são avaliadas. Quando uma correspondência parcial é feita, as regras match aninhada são testadas para verificar se algum path aninhado completará a correspondência.

As regras em cada match completa são avaliadas para determinar se a solicitação deve ser permitida. Se alguma regra correspondente conceder acesso, a solicitação será permitida. Se nenhuma regra correspondente conceder acesso, a solicitação será negada.

// Given request.path == /example/hello/nested/path the following
// declarations indicate whether they are a partial or complete match and
// the value of any variables visible within the scope.
service firebase.storage {
  // Partial match.
  match /example/{singleSegment} {   // `singleSegment` == 'hello'
    allow write;                     // Write rule not evaluated.
    // Complete match.
    match /nested/path {             // `singleSegment` visible in scope.
      allow read;                    // Read rule is evaluated.
    }
  }
  // Complete match.
  match /example/{multiSegment=**} { // `multiSegment` == /hello/nested/path
    allow read;                      // Read rule is evaluated.
  }
}

Como mostra o exemplo acima, as declarações path suportam as seguintes variáveis:

  • Curinga de segmento único: uma variável curinga é declarada em um caminho envolvendo uma variável entre chaves: {variable} . Esta variável pode ser acessada na instrução match como uma string .
  • Curinga recursivo: o curinga recursivo ou de vários segmentos corresponde a vários segmentos de caminho em ou abaixo de um caminho. Este curinga corresponde a todos os caminhos abaixo do local definido. Você pode declará-lo adicionando a string =** no final da sua variável de segmento: {variable=**} . Esta variável pode ser acessada na instrução match como um objeto path .

Permitir

O bloco match contém uma ou mais instruções allow . Estas são suas regras reais. Você pode aplicar regras allow a um ou mais métodos. As condições em uma instrução allow devem ser avaliadas como verdadeiras para que o Cloud Firestore ou o Cloud Storage concedam qualquer solicitação recebida. Você também pode escrever instruções allow sem condições, por exemplo, allow read . Entretanto, se a instrução allow não incluir uma condição, ela sempre permitirá a solicitação desse método.

Se alguma das regras allow do método for satisfeita, a solicitação será permitida. Além disso, se uma regra mais ampla conceder acesso, as Regras concederão acesso e ignorarão quaisquer regras mais granulares que possam limitar o acesso.

Considere o exemplo a seguir, onde qualquer usuário pode ler ou excluir qualquer um de seus próprios arquivos. Uma regra mais granular só permite gravações se o usuário que solicita a gravação for proprietário do arquivo e o arquivo for um PNG. Um usuário pode excluir qualquer arquivo no subcaminho — mesmo que não sejam PNGs — porque a regra anterior permite isso.

service firebase.storage {
  // Allow the requestor to read or delete any resource on a path under the
  // user directory.
  match /users/{userId}/{anyUserFile=**} {
    allow read, delete: if request.auth != null && request.auth.uid == userId;
  }

  // Allow the requestor to create or update their own images.
  // When 'request.method' == 'delete' this rule and the one matching
  // any path under the user directory would both match and the `delete`
  // would be permitted.

  match /users/{userId}/images/{imageId} {
    // Whether to permit the request depends on the logical OR of all
    // matched rules. This means that even if this rule did not explicitly
    // allow the 'delete' the earlier rule would have.
    allow write: if request.auth != null && request.auth.uid == userId && imageId.matches('*.png');
  }
}

Método

Cada instrução allow inclui um método que concede acesso para solicitações recebidas do mesmo método.

Método Tipo de solicitação
Métodos de conveniência
read Qualquer tipo de solicitação de leitura
write Qualquer tipo de solicitação de gravação
Métodos padrão
get Leia solicitações para documentos ou arquivos únicos
list Ler solicitações de consultas e coleções
create Escreva novos documentos ou arquivos
update Grave em documentos de banco de dados existentes ou atualize metadados de arquivos
delete Excluir dados

Você não pode sobrepor métodos de leitura no mesmo bloco match ou métodos de gravação conflitantes na mesma declaração path .

Por exemplo, as seguintes regras falhariam:

service bad.example {
  match /rules/with/overlapping/methods {
    // This rule allows reads to all authenticated users
    allow read: if request.auth != null;

    match another/subpath {
      // This secondary, more specific read rule causes an error
      allow get: if request.auth != null && request.auth.uid == "me";
      // Overlapping write methods in the same path cause an error as well
      allow write: if request.auth != null;
      allow create: if request.auth != null && request.auth.uid == "me";
    }
  }
}

Função

À medida que suas regras de segurança se tornam mais complexas, você pode querer agrupar conjuntos de condições em funções que podem ser reutilizadas em seu conjunto de regras. As regras de segurança suportam funções personalizadas. A sintaxe para funções personalizadas é um pouco parecida com JavaScript, mas as funções de regras de segurança são escritas em uma linguagem específica de domínio que tem algumas limitações importantes:

  • As funções podem conter apenas uma única instrução return . Eles não podem conter nenhuma lógica adicional. Por exemplo, eles não podem executar loops ou chamar serviços externos.
  • As funções podem acessar automaticamente funções e variáveis ​​do escopo em que estão definidas. Por exemplo, uma função definida no escopo service cloud.firestore tem acesso à variável resource e funções integradas, como get() e exists() .
  • As funções podem chamar outras funções, mas não podem recorrer. A profundidade total da pilha de chamadas é limitada a 20.
  • Na versão de regras v2 , as funções podem definir variáveis ​​usando a palavra-chave let . As funções podem ter até 10 ligações let, mas devem terminar com uma instrução return.

Uma função é definida com a palavra-chave function e aceita zero ou mais argumentos. Por exemplo, você pode querer combinar os dois tipos de condições usadas nos exemplos acima em uma única função:

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

Aqui está um exemplo mostrando argumentos de função e atribuições let. Deixe que as instruções de atribuição sejam separadas por ponto e vírgula.

function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  let isAdmin = exists(/databases/$(database)/documents/admins/$(userId));
  return isAuthor || isAdmin;
}

Observe como a atribuição isAdmin impõe uma pesquisa na coleção admins. Para avaliação lenta sem exigir pesquisas desnecessárias, aproveite a natureza de curto-circuito de && (AND) e || (OR) comparações para chamar uma segunda função somente se isAuthor for mostrado como verdadeiro (para comparações && ) ou falso (para comparações || ).

function isAdmin(userId) {
  return exists(/databases/$(database)/documents/admins/$(userId));
}
function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  // `||` is short-circuiting; isAdmin called only if isAuthor == false.
  return isAuthor || isAdmin(userId);
}

O uso de funções em suas regras de segurança torna-as mais fáceis de manter à medida que a complexidade de suas regras aumenta.

Banco de dados em tempo real

Conforme descrito acima, as regras do Realtime Database incluem três elementos básicos: a localização do banco de dados como um espelho da estrutura JSON do banco de dados, o tipo de solicitação e a condição que concede acesso.

Localização do banco de dados

A estrutura das suas regras deve seguir a estrutura dos dados armazenados no seu banco de dados. Por exemplo, em um aplicativo de bate-papo com uma lista de mensagens, você pode ter dados semelhantes a estes:

  {
    "messages": {
      "message0": {
        "content": "Hello",
        "timestamp": 1405704370369
      },
      "message1": {
        "content": "Goodbye",
        "timestamp": 1405704395231
      },
      ...
    }
  }

Suas regras devem espelhar essa estrutura. Por exemplo:

  {
    "rules": {
      "messages": {
        "$message": {
          // only messages from the last ten minutes can be read
          ".read": "data.child('timestamp').val() > (now - 600000)",

          // new messages must have a string content and a number timestamp
          ".validate": "newData.hasChildren(['content', 'timestamp']) &&
                        newData.child('content').isString() &&
                        newData.child('timestamp').isNumber()"
        }
      }
    }
  }

Como mostra o exemplo acima, as regras do Realtime Database oferecem suporte a uma variável $location para corresponder aos segmentos de caminho. Use o prefixo $ na frente do segmento do caminho para combinar sua regra com qualquer nó filho ao longo do caminho.

  {
    "rules": {
      "rooms": {
        // This rule applies to any child of /rooms/, the key for each room id
        // is stored inside $room_id variable for reference
        "$room_id": {
          "topic": {
            // The room's topic can be changed if the room id has "public" in it
            ".write": "$room_id.contains('public')"
          }
        }
      }
    }
  }

Você também pode usar a $variable em paralelo com nomes de caminhos constantes.

  {
    "rules": {
      "widget": {
        // a widget can have a title or color attribute
        "title": { ".validate": true },
        "color": { ".validate": true },

        // but no other child paths are allowed
        // in this case, $other means any key excluding "title" and "color"
        "$other": { ".validate": false }
      }
    }
  }

Método

No Realtime Database, existem três tipos de regras. Dois desses tipos de regras — read e write — aplicam-se ao método de uma solicitação recebida. O tipo de regra validate impõe estruturas de dados e valida o formato e o conteúdo dos dados. As regras executam regras .validate após verificar se uma regra .write concede acesso.

Tipos de regras
.ler Descreve se e quando os dados podem ser lidos pelos usuários.
.escrever Descreve se e quando os dados podem ser gravados.
.validar Define a aparência de um valor formatado corretamente, se ele possui atributos filho e o tipo de dados.

Por padrão, se não houver uma regra que permita isso, o acesso a um caminho será negado.

Condições de construção

Cloud Firestore

Uma condição é uma expressão booleana que determina se uma determinada operação deve ser permitida ou negada. As variáveis request e resource fornecem contexto para essas condições.

A variável request

A variável request inclui os seguintes campos e informações correspondentes:

request.auth

Um JSON Web Token (JWT) que contém credenciais de autenticação do Firebase Authentication. O token auth contém um conjunto de declarações padrão e quaisquer declarações personalizadas criadas por meio do Firebase Authentication. Saiba mais sobre regras de segurança e autenticação do Firebase .

request.method

O request.method pode ser qualquer um dos métodos padrão ou um método personalizado. Os métodos de conveniência read e write também existem para simplificar as regras de escrita que se aplicam a todos os métodos padrão somente leitura ou somente gravação, respectivamente.

request.params

Os request.params incluem quaisquer dados não relacionados especificamente ao request.resource que possam ser úteis para avaliação. Na prática, este mapa deve estar vazio para todos os métodos padrão e deve conter dados que não sejam de recursos para métodos personalizados. Os serviços devem ter cuidado para não renomear ou modificar o tipo de qualquer uma das chaves e valores apresentados como parâmetros.

request.path

O request.path é o caminho para o resource de destino. O caminho é relativo ao serviço. Segmentos de caminho contendo caracteres não seguros para URL, como / são codificados por URL.

A variável resource

O resource é o valor atual dentro do serviço representado como um mapa de pares chave-valor. Referenciar resource dentro de uma condição resultará em no máximo uma leitura do valor do serviço. Esta pesquisa será contabilizada em qualquer cota relacionada ao serviço do recurso. Para solicitações get , o resource só será contabilizado na cota em caso de negação.

Operadores e precedência de operador

Use a tabela abaixo como referência para operadores e suas precedências correspondentes em Regras para Cloud Firestore e Cloud Storage.

Dadas expressões arbitrárias a e b , um campo f e um índice i .

Operador Descrição Associatividade
a[i] a() af Índice, chamada, acesso ao campo da esquerda para direita
!a -a Negação unária direita para esquerda
a/ba%ba*b Operadores multiplicativos da esquerda para direita
a+b ab Operadores aditivos da esquerda para direita
a>ba>=ba Operadores relacionais da esquerda para direita
a in b Existência em lista ou mapa da esquerda para direita
a is type Comparação de tipos, onde type pode ser bool, int, float, número, string, lista, mapa, carimbo de data/hora, duração, caminho ou latlng da esquerda para direita
a==ba!=b Operadores de comparação da esquerda para direita
a && b Condicional E da esquerda para direita
a || b OU condicional da esquerda para direita
a ? true_value : false_value Expressão ternária da esquerda para direita

Armazenamento na núvem

Uma condição é uma expressão booleana que determina se uma determinada operação deve ser permitida ou negada. As variáveis request e resource fornecem contexto para essas condições.

A variável request

A variável request inclui os seguintes campos e informações correspondentes:

request.auth

Um JSON Web Token (JWT) que contém credenciais de autenticação do Firebase Authentication. O token auth contém um conjunto de declarações padrão e quaisquer declarações personalizadas criadas por meio do Firebase Authentication. Saiba mais sobre regras de segurança e autenticação do Firebase .

request.method

O request.method pode ser qualquer um dos métodos padrão ou um método personalizado. Os métodos de conveniência read e write também existem para simplificar as regras de escrita que se aplicam a todos os métodos padrão somente leitura ou somente gravação, respectivamente.

request.params

Os request.params incluem quaisquer dados não relacionados especificamente ao request.resource que possam ser úteis para avaliação. Na prática, este mapa deve estar vazio para todos os métodos padrão e deve conter dados que não sejam de recursos para métodos personalizados. Os serviços devem ter cuidado para não renomear ou modificar o tipo de qualquer uma das chaves e valores apresentados como parâmetros.

request.path

O request.path é o caminho para o resource de destino. O caminho é relativo ao serviço. Segmentos de caminho contendo caracteres não seguros para URL, como / são codificados por URL.

A variável resource

O resource é o valor atual dentro do serviço representado como um mapa de pares chave-valor. Referenciar resource dentro de uma condição resultará em no máximo uma leitura do valor do serviço. Esta pesquisa será contabilizada em qualquer cota relacionada ao serviço do recurso. Para solicitações get , o resource só será contabilizado na cota em caso de negação.

Operadores e precedência de operador

Use a tabela abaixo como referência para operadores e suas precedências correspondentes em Regras para Cloud Firestore e Cloud Storage.

Dadas expressões arbitrárias a e b , um campo f e um índice i .

Operador Descrição Associatividade
a[i] a() af Índice, chamada, acesso ao campo da esquerda para direita
!a -a Negação unária direita para esquerda
a/ba%ba*b Operadores multiplicativos da esquerda para direita
a+b ab Operadores aditivos da esquerda para direita
a>ba>=ba Operadores relacionais da esquerda para direita
a in b Existência em lista ou mapa da esquerda para direita
a is type Comparação de tipos, onde type pode ser bool, int, float, número, string, lista, mapa, carimbo de data/hora, duração, caminho ou latlng da esquerda para direita
a==ba!=b Operadores de comparação da esquerda para direita
a && b Condicional E da esquerda para direita
a || b OU condicional da esquerda para direita
a ? true_value : false_value Expressão ternária da esquerda para direita

Banco de dados em tempo real

Uma condição é uma expressão booleana que determina se uma determinada operação deve ser permitida ou negada. Você pode definir essas condições nas regras do Realtime Database das seguintes maneiras.

Variáveis ​​pré-definidas

Há diversas variáveis ​​úteis e predefinidas que podem ser acessadas dentro de uma definição de regra. Aqui está um breve resumo de cada um:

Variáveis ​​predefinidas
agora A hora atual em milissegundos desde a época do Linux. Isso funciona particularmente bem para validar carimbos de data/hora criados com firebase.database.ServerValue.TIMESTAMP do SDK.
raiz Um RuleDataSnapshot que representa o caminho raiz no banco de dados Firebase conforme ele existia antes da tentativa de operação.
novos dados Um RuleDataSnapshot que representa os dados como existiriam após a tentativa de operação. Inclui os novos dados que estão sendo gravados e os dados existentes.
dados Um RuleDataSnapshot que representa os dados como existiam antes da tentativa de operação.
$variáveis Um caminho curinga usado para representar ids e chaves filhas dinâmicas.
autenticação Representa a carga de token de um usuário autenticado.

Essas variáveis ​​podem ser usadas em qualquer lugar nas suas regras. Por exemplo, as regras de segurança abaixo garantem que os dados gravados no nó /foo/ devem ser uma string com menos de 100 caracteres:

{
  "rules": {
    "foo": {
      // /foo is readable by the world
      ".read": true,

      // /foo is writable by the world
      ".write": true,

      // data written to /foo must be a string less than 100 characters
      ".validate": "newData.isString() && newData.val().length < 100"
    }
  }
}

Regras baseadas em dados

Quaisquer dados em seu banco de dados podem ser usados ​​em suas regras. Usando as variáveis ​​predefinidas root , data e newData , você pode acessar qualquer caminho que existiria antes ou depois de um evento de gravação.

Considere este exemplo, que permite operações de gravação, desde que o valor do nó /allow_writes/ seja true , o nó pai não tenha um sinalizador readOnly definido e haja um filho chamado foo nos dados recém-escritos:

".write": "root.child('allow_writes').val() === true &&
          !data.parent().child('readOnly').exists() &&
          newData.child('foo').exists()"

Regras baseadas em consulta

Embora não seja possível usar regras como filtros, você pode limitar o acesso a subconjuntos de dados usando parâmetros de consulta em suas regras. Usar query. expressões em suas regras para conceder acesso de leitura ou gravação com base em parâmetros de consulta.

Por exemplo, a regra baseada em consulta a seguir usa regras de segurança baseadas no usuário e regras baseadas em consulta para restringir o acesso aos dados na coleção de baskets apenas aos carrinhos de compras que o usuário ativo possui:

"baskets": {
  ".read": "auth.uid !== null &&
            query.orderByChild === 'owner' &&
            query.equalTo === auth.uid" // restrict basket access to owner of basket
}

A consulta a seguir, que inclui os parâmetros de consulta na regra, seria bem-sucedida:

db.ref("baskets").orderByChild("owner")
                 .equalTo(auth.currentUser.uid)
                 .on("value", cb)                 // Would succeed

No entanto, as consultas que não incluíssem os parâmetros na regra falhariam com um erro PermissionDenied :

db.ref("baskets").on("value", cb)                 // Would fail with PermissionDenied

Você também pode usar regras baseadas em consulta para limitar a quantidade de dados que um cliente baixa por meio de operações de leitura.

Por exemplo, a regra a seguir limita o acesso de leitura apenas aos primeiros 1.000 resultados de uma consulta, conforme ordenado por prioridade:

messages: {
  ".read": "query.orderByKey &&
            query.limitToFirst <= 1000"
}

// Example queries:

db.ref("messages").on("value", cb)                // Would fail with PermissionDenied

db.ref("messages").limitToFirst(1000)
                  .on("value", cb)                // Would succeed (default order by key)

A seguinte query. expressões estão disponíveis em Regras de segurança do Realtime Database.

Expressões de regras baseadas em consulta
Expressão Tipo Descrição
consulta.orderByKey
query.orderByPriority
consulta.orderByValue
boleano Verdadeiro para consultas ordenadas por chave, prioridade ou valor. Caso contrário, falso.
consulta.orderByChild corda
nulo
Use uma string para representar o caminho relativo para um nó filho. Por exemplo, query.orderByChild === "address/zip" . Se a consulta não for ordenada por um nó filho, esse valor será nulo.
consulta.startAt
consulta.endAt
consulta.equalTo
corda
número
boleano
nulo
Recupera os limites da consulta em execução ou retorna nulo se não houver nenhum conjunto de limites.
consulta.limitToFirst
query.limitToLast
número
nulo
Recupera o limite da consulta em execução ou retorna nulo se não houver limite definido.

Operadores

As regras do Realtime Database oferecem suporte a vários operadores que você pode usar para combinar variáveis ​​na instrução de condição. Veja a lista completa de operadores na documentação de referência .

Criando condições

Suas condições reais variam de acordo com o acesso que você deseja conceder. As regras oferecem intencionalmente um enorme grau de flexibilidade, de modo que as regras do seu aplicativo podem ser tão simples ou complexas quanto você precisar.

Para obter orientação sobre como criar regras simples e prontas para produção, consulte Regras básicas de segurança .