Catch up on everthing we announced at this year's Firebase Summit. Learn more

Aprenda a sintaxe principal da linguagem de regras do Realtime Database

As regras de segurança do Firebase Realtime Database permitem que você controle o acesso aos dados armazenados em seu banco de dados. A sintaxe de regras flexíveis permite criar regras que correspondem a qualquer coisa, desde todas as gravações em seu banco de dados até operações em nós individuais.

De banco de dados em tempo real regras de segurança são configuração declarativa para o seu banco de dados. Isso significa que as regras são definidas separadamente da lógica do produto. Isso tem uma série de vantagens: os clientes não são responsáveis ​​por garantir a segurança, as implementações com erros não comprometerão seus dados e, talvez o mais importante, não há necessidade de um árbitro intermediário, como um servidor, para proteger os dados do mundo.

Este tópico descreve a sintaxe básica e a estrutura Regras de segurança do Realtime Database usadas para criar conjuntos de regras completos.

Estruturar suas regras de segurança

As regras de segurança do Realtime Database são compostas por expressões semelhantes a JavaScript contidas em um documento JSON. A estrutura de suas regras deve seguir a estrutura dos dados armazenados em seu banco de dados.

Regras básicas identificar um conjunto de nós a ser protegido, os métodos de acesso (por exemplo, ler, escrever) envolvidos, e as condições sob as quais o acesso é permitido ou negado. Nos exemplos a seguir, nossas condições será simples true e false declarações, mas no próximo tópico abordaremos formas mais dinâmicas para expressar condições.

Assim, por exemplo, se estamos a tentar garantir um child_node sob uma parent_node , a sintaxe geral a seguir é:

{
  "rules": {
    "parent_node": {
      "child_node": {
        ".read": <condition>,
        ".write": <condition>,
        ".validate": <condition>,
      }
    }
  }
}

Vamos aplicar esse padrão. Por exemplo, digamos que você esteja acompanhando uma lista de mensagens e tenha dados parecidos com estes:

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

Suas regras devem ser estruturadas de maneira semelhante. Aqui está um conjunto de regras para segurança somente leitura que pode fazer sentido para essa estrutura de dados. Este exemplo ilustra como especificamos os nós do banco de dados aos quais as regras se aplicam e as condições para avaliar as regras nesses nós.

{
  "rules": {
    // For requests to access the 'messages' node...
    "messages": {
      // ...and the individual wildcarded 'message' nodes beneath
      // (we'll cover wildcarding variables more a bit later)....
      "$message": {

        // For each message, allow a read operation if <condition>. In this
        // case, we specify our condition as "true", so read access is always granted.
        ".read": "true",

        // For read-only behavior, we specify that for write operations, our
        // condition is false.
        ".write": "false"
      }
    }
  }
}

Operações de regras básicas

Existem três tipos de regras para reforçar a segurança com base no tipo de operação a ser realizada nos dados: .write , .read e .validate . Aqui está um rápido resumo de seus objetivos:

Tipos de regra
.leitura 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 possui atributos filho e o tipo de dados.

Variáveis ​​de captura de curinga

Todas as declarações de regras apontam para nós. A declaração pode apontar para um nó específico ou usar $ variáveis de captura de curinga para apontar para conjuntos de nós em um nível da hierarquia. Use essas variáveis ​​de captura para armazenar o valor das chaves do nó para uso nas instruções de regras subsequentes. Esta técnica permite que você escreva condições regras mais complexas, algo que vamos cobrir mais detalhadamente no próximo tópico.

{
  "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')"
        }
      }
    }
  }
}

Os dinâmica $ variáveis também podem ser usados em paralelo com nomes de caminho constantes. Neste exemplo, estamos usando o $other variável para declarar uma .validate regra que garante que widget não tem outros do que as crianças title e color . Qualquer gravação que resultasse na criação de filhos adicionais falharia.

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

Cascata de regras de leitura e gravação

.read e .write regras trabalhar a partir de cima para baixo, com regras mais rasas imperiosas regras mais profundas. Se uma regra bolsas de ler ou permissões de gravação em um caminho particular, então ele também concede acesso a todos os nós filho sob ele. Considere a seguinte estrutura:

{
  "rules": {
     "foo": {
        // allows read to /foo/*
        ".read": "data.child('baz').val() === true",
        "bar": {
          /* ignored, since read was allowed already */
          ".read": false
        }
     }
  }
}

Esta estrutura de segurança permite /bar/ para ser lido a partir sempre /foo/ contém uma criança baz com o valor true . O ".read": false regra sob /foo/bar/ não tem efeito aqui, já que o acesso não pode ser revogada por um caminho filho.

Embora possa não parecer intuitivo imediatamente, esta é uma parte poderosa da linguagem de regras e permite que privilégios de acesso muito complexos sejam implementados com o mínimo de esforço. Isso será ilustrado quando entrarmos na segurança baseada no usuário mais adiante neste guia.

Note-se que .validate regras não cascata. Todas as regras de validação devem ser satisfeitas em todos os níveis da hierarquia para que uma gravação seja permitida.

Regras não são filtros

As regras são aplicadas de maneira atômica. Isso significa que uma operação de leitura ou gravação falha imediatamente se não houver uma regra naquele local ou em um local pai que conceda acesso. Mesmo se cada caminho filho afetado estiver acessível, a leitura no local pai falhará completamente. Considere esta estrutura:

{
  "rules": {
    "records": {
      "rec1": {
        ".read": true
      },
      "rec2": {
        ".read": false
      }
    }
  }
}

Sem compreender que as regras são avaliadas atomicamente, pode parecer que buscar o /records/ caminho voltaria rec1 mas não rec2 . O resultado real, no entanto, é um erro:

JavaScript
var db = firebase.database();
db.ref("records").once("value", function(snap) {
  // success method is not called
}, function(err) {
  // error callback triggered with PERMISSION_DENIED
});
Objective-C
Nota: Este produto Firebase não está disponível no alvo Clipe App.
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[_ref child:@"records"] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  // success block is not called
} withCancelBlock:^(NSError * _Nonnull error) {
  // cancel block triggered with PERMISSION_DENIED
}];
Rápido
Nota: Este produto Firebase não está disponível no alvo Clipe App.
var ref = FIRDatabase.database().reference()
ref.child("records").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // success block is not called
}, withCancelBlock: { error in
    // cancel block triggered with PERMISSION_DENIED
})
Java
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("records");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    // success method is not called
  }

  @Override
  public void onCancelled(FirebaseError firebaseError) {
    // error callback triggered with PERMISSION_DENIED
  });
});
DESCANSO
curl https://docs-examples.firebaseio.com/rest/records/
# response returns a PERMISSION_DENIED error

Desde a operação de leitura em /records/ é atômica, e não há nenhuma regra leitura que concede acesso a todos os dados sob /records/ , isso vai jogar um PERMISSION_DENIED erro. Se avaliarmos esta regra no simulador de segurança em nossa consola Firebase , podemos ver que a operação de leitura foi negado porque nenhuma regra leitura permitido o acesso ao /records/ caminho. No entanto, nota que a regra para rec1 não foi avaliada porque não estava no caminho que solicitado. Para buscar rec1 , seria preciso acessá-lo diretamente:

JavaScript
var db = firebase.database();
db.ref("records/rec1").once("value", function(snap) {
  // SUCCESS!
}, function(err) {
  // error callback is not called
});
Objective-C
Nota: Este produto Firebase não está disponível no alvo Clipe App.
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[ref child:@"records/rec1"] observeSingleEventOfType:FEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
    // SUCCESS!
}];
Rápido
Nota: Este produto Firebase não está disponível no alvo Clipe App.
var ref = FIRDatabase.database().reference()
ref.child("records/rec1").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // SUCCESS!
})
Java
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("records/rec1");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    // SUCCESS!
  }

  @Override
  public void onCancelled(FirebaseError firebaseError) {
    // error callback is not called
  }
});
DESCANSO
curl https://docs-examples.firebaseio.com/rest/records/rec1
# SUCCESS!

Declarações sobrepostas

É possível que mais de uma regra se aplique a um nó. No caso em que várias regras expressões identificar um nó, o método de acesso é negado se qualquer uma das condições é false :

{
  "rules": {
    "messages": {
      // A rule expression that applies to all nodes in the 'messages' node
      "$message": {
        ".read": "true",
        ".write": "true"
      },
      // A second rule expression applying specifically to the 'message1` node
      "message1": {
        ".read": "false",
        ".write": "false"
      }
    }
  }
}

No exemplo acima, lê ao message1 nó será negado porque o segundo regras é sempre false , embora a primeira regra é sempre true .

Próximos passos

Você pode aprofundar seus conhecimentos sobre as regras de segurança do Firebase Realtime Database:

  • Saiba o próximo grande conceito da língua Regras, dinâmicas condições , que permitem que as suas regras de verificação de autorização do usuário, comparar os dados existentes e recebidas, validar dados de entrada, verifique a estrutura de consultas provenientes do cliente, e muito mais.

  • Comente casos de uso de segurança típicos e as definições de regras de segurança Firebase que o endereço deles .