Catch up on everything announced at Firebase Summit, and learn how Firebase can help you accelerate app development and run your app with confidence. Learn More

Idioma das regras de segurança

Mantenha tudo organizado com as coleções Salve e categorize o conteúdo com base nas suas preferências.

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

Como essas são linguagens personalizadas, no entanto, há uma curva de aprendizado. Use este guia para entender melhor a linguagem de 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>>
  }
}

Os seguintes conceitos-chave são importantes para entender à medida que você cria as regras:

  • Request: O método ou métodos invocados na instrução de allow . Estes são os métodos que você está permitindo a execução. Os métodos padrão são: get , list , create , update e delete . Os métodos de conveniência 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 de URI.
  • Regra: A instrução allow , que inclui uma condição que permite uma solicitação se ela for avaliada como verdadeira.

Cada um desses conceitos é descrito com mais detalhes a seguir.

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>>
  }
}

Os seguintes conceitos-chave são importantes para entender à medida que você cria as regras:

  • Request: O método ou métodos invocados na instrução de allow . Estes são os métodos que você está permitindo a execução. Os métodos padrão são: get , list , create , update e delete . Os métodos de conveniência 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 de URI.
  • Regra: A instrução allow , que inclui uma condição que permite uma solicitação se ela for avaliada como verdadeira.

Cada um desses conceitos é descrito com mais detalhes a seguir.

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 espelha a estrutura JSON do seu banco de dados.
  • Request: Esses são os métodos que a regra usa para conceder acesso. As regras de read e write concedem amplo acesso de leitura e gravação, enquanto as regras de 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 de 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 de conveniência read e write .
  • Declarações de function opcionais: fornecem a capacidade de combinar e agrupar condições para uso em várias regras.

O service contém um ou mais blocos de match com instruções de allow que fornecem condições que concedem acesso a solicitações. As variáveis ​​de request e resource estão disponíveis para uso em condições de regra. A linguagem Firebase Security Rules também é compatível com declarações de function .

Versão da sintaxe

A instrução de syntax indica a versão da linguagem Firebase Rules usada para gravar a origem. A versão mais recente do idioma é 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 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 Firebase CLI, precisará mantê-las em arquivos separados.

Combine

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

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

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

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

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

As regras em cada match completa são avaliadas para determinar se a solicitação deve ser permitida. Se alguma regra de correspondência 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 de 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} . Essa variável é acessível dentro da instrução match como uma string .
  • Curinga recursivo: O curinga recursivo ou de vários segmentos corresponde a vários segmentos de caminho em um caminho ou abaixo dele. Este curinga corresponde a todos os caminhos abaixo do local para o qual você o definiu. Você pode declará-lo adicionando a string =** no final de sua variável de segmento: {variable=**} . Essa variável é acessível dentro da instrução match como um objeto de path .

Permitir

O bloco de match contém uma ou mais instruções de allow . Estas são suas regras reais. Você pode aplicar regras de allow a um ou mais métodos. As condições em uma instrução de 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 . Se a instrução allow não incluir uma condição, no entanto, ela sempre permitirá a solicitação desse método.

Se alguma das regras de allow para o método for atendida, 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 o 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 de 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 de documentos ou arquivos únicos
list Ler solicitações de consultas e coletas
create Escreva novos documentos ou arquivos
update Gravar em documentos de banco de dados existentes ou atualizar metadados de arquivo
delete Excluir dados

Você não pode sobrepor métodos de leitura no mesmo bloco de match ou métodos de gravação conflitantes na mesma declaração de 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 possui algumas limitações importantes:

  • As funções podem conter apenas uma única instrução de 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 são definidas. Por exemplo, uma função definida no escopo do service cloud.firestore tem acesso à variável de resource e funções internas, como get() e exists() .
  • As funções podem chamar outras funções, mas não podem ser recursivas. 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 recebe zero ou mais argumentos. Por exemplo, você pode querer combinar os dois tipos de condições usados ​​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. Let instruções de atribuição devem ser 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 da coleção de administradores. Para avaliação lenta sem exigir pesquisas desnecessárias, aproveite a natureza de curto-circuito de && (AND) e || (OR) para chamar uma segunda função somente se isAuthor for mostrado como true (para && comparações) ou false (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 as torna 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 de 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 de conveniência read e write .
  • Declarações de function opcionais: fornecem a capacidade de combinar e agrupar condições para uso em várias regras.

O service contém um ou mais blocos de match com instruções de allow que fornecem condições que concedem acesso a solicitações. As variáveis ​​de request e resource estão disponíveis para uso em condições de regra. A linguagem Firebase Security Rules também é compatível com declarações de function .

Versão da sintaxe

A instrução de syntax indica a versão da linguagem Firebase Rules usada para gravar a origem. A versão mais recente do idioma é 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 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 Firebase CLI, precisará mantê-las em arquivos separados.

Combine

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

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

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

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

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

As regras em cada match completa são avaliadas para determinar se a solicitação deve ser permitida. Se alguma regra de correspondência 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 de 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} . Essa variável é acessível dentro da instrução match como uma string .
  • Curinga recursivo: O curinga recursivo ou de vários segmentos corresponde a vários segmentos de caminho em um caminho ou abaixo dele. Este curinga corresponde a todos os caminhos abaixo do local para o qual você o definiu. Você pode declará-lo adicionando a string =** no final de sua variável de segmento: {variable=**} . Essa variável é acessível dentro da instrução match como um objeto de path .

Permitir

O bloco de match contém uma ou mais instruções de allow . Estas são suas regras reais. Você pode aplicar regras de allow a um ou mais métodos. As condições em uma instrução de 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 . Se a instrução allow não incluir uma condição, no entanto, ela sempre permitirá a solicitação desse método.

Se alguma das regras de allow para o método for atendida, 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 o 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 de 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 de documentos ou arquivos únicos
list Ler solicitações de consultas e coletas
create Escreva novos documentos ou arquivos
update Gravar em documentos de banco de dados existentes ou atualizar metadados de arquivo
delete Excluir dados

Você não pode sobrepor métodos de leitura no mesmo bloco de match ou métodos de gravação conflitantes na mesma declaração de 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 possui algumas limitações importantes:

  • As funções podem conter apenas uma única instrução de 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 são definidas. Por exemplo, uma função definida no escopo do service cloud.firestore tem acesso à variável de resource e funções internas, como get() e exists() .
  • As funções podem chamar outras funções, mas não podem ser recursivas. 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 recebe zero ou mais argumentos. Por exemplo, você pode querer combinar os dois tipos de condições usados ​​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. Let instruções de atribuição devem ser 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 da coleção de administradores. Para avaliação lenta sem exigir pesquisas desnecessárias, aproveite a natureza de curto-circuito de && (AND) e || (OR) para chamar uma segunda função somente se isAuthor for mostrado como true (para && comparações) ou false (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 as torna 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: o local do banco de dados como um espelho da estrutura JSON do banco de dados, o tipo de solicitação e a condição de concessão de acesso.

Local do banco de dados

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

  {
    "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 são compatíveis com uma variável $location para corresponder a segmentos de caminho. Use o prefixo $ na frente de seu segmento de caminho para corresponder sua regra a 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 — se aplicam ao método de uma solicitação recebida. O tipo de regra de validate impõe estruturas de dados e valida o formato e o conteúdo dos dados. As regras executam regras .validate depois de verificar se uma regra .write concede acesso.

Tipos de regras
.ler Descreve se e quando os dados podem ser lidos pelos usuários.
.Escreva 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 o permita, o acesso em um caminho é 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 ​​de request e resource fornecem contexto para essas condições.

A variável de request

A variável de 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. auth token contém um conjunto de declarações padrão e quaisquer declarações personalizadas que você criar por meio do Firebase Authentication. Saiba mais sobre as 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 especificamente relacionados ao request.resource que podem ser úteis para avaliação. Na prática, esse 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 nenhuma 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. Os segmentos de caminho que contêm caracteres não seguros para URL, como / , são codificados por URL.

A variável de resource

O resource é o valor atual dentro do serviço representado como um mapa de pares chave-valor. O resource de referência em uma condição resultará em no máximo uma leitura do valor do serviço. Essa pesquisa será contabilizada em qualquer cota relacionada ao serviço para o recurso. Para solicitações de get , o resource contará apenas para a cota em caso de negação.

Operadores e precedência de operadores

Use a tabela abaixo como referência para operadores e sua precedência correspondente em Regras para Cloud Firestore e Cloud Storage.

Dadas expressões arbitrárias a e b , um corpo 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 na lista ou mapa da esquerda para direita
a is type Comparação de tipos, onde o type pode ser bool, int, float, number, string, list, map, timestamp, duration, path ou latlng da esquerda para direita
a==ba!=b Operadores de comparação da esquerda para direita
a && b E condicional 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 ​​de request e resource fornecem contexto para essas condições.

A variável de request

A variável de 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. auth token contém um conjunto de declarações padrão e quaisquer declarações personalizadas que você criar por meio do Firebase Authentication. Saiba mais sobre as 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 especificamente relacionados ao request.resource que podem ser úteis para avaliação. Na prática, esse 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 nenhuma 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. Os segmentos de caminho que contêm caracteres não seguros para URL, como / , são codificados por URL.

A variável de resource

O resource é o valor atual dentro do serviço representado como um mapa de pares chave-valor. O resource de referência em uma condição resultará em no máximo uma leitura do valor do serviço. Essa pesquisa será contabilizada em qualquer cota relacionada ao serviço para o recurso. Para solicitações de get , o resource contará apenas para a cota em caso de negação.

Operadores e precedência de operadores

Use a tabela abaixo como referência para operadores e sua precedência correspondente em Regras para Cloud Firestore e Cloud Storage.

Dadas expressões arbitrárias a e b , um corpo 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 na lista ou mapa da esquerda para direita
a is type Comparação de tipos, onde o type pode ser bool, int, float, number, string, list, map, timestamp, duration, path ou latlng da esquerda para direita
a==ba!=b Operadores de comparação da esquerda para direita
a && b E condicional 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 maneiras a seguir.

Variáveis ​​predefinidas

Há várias variáveis ​​pré-definidas úteis 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 do Firebase como existia antes da tentativa de operação.
novos dados Um RuleDataSnapshot representando 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 representando 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 útil do token de um usuário autenticado.

Essas variáveis ​​podem ser usadas em qualquer lugar em suas regras. Por exemplo, as regras de segurança abaixo garantem que os dados gravados no nó /foo/ sejam 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 como 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-gravados:

".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 seguinte regra baseada em consulta usa regras de segurança baseadas em usuário e regras baseadas em consulta para restringir o acesso aos dados na coleção de baskets apenas às cestas 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 incluem 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 do Realtime Database.

Expressões de regra baseadas em consulta
Expressão Modelo Descrição
query.orderByKey
query.orderByPriority
query.orderByValue
boleano True para consultas ordenadas por chave, prioridade ou valor. Falso caso contrário.
query.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.
query.startAt
query.endAt
query.equalTo
corda
número
boleano
nulo
Recupera os limites da consulta em execução ou retorna null se não houver um conjunto de limites.
query.limitToFirst
query.limitToLast
número
nulo
Recupera o limite na consulta em execução ou retorna null 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. Consulte 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 tão complexas quanto você precisar.

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