É possível usar as regras de segurança do Firebase para gravar, de modo condicional, novos dados com base nas informações presentes no banco de dados ou no bucket de armazenamento. Além disso, é possível gravar regras que apliquem validações de dados por meio da restrição de gravações com base nos novos dados que estão sendo gravados. Continue lendo para saber mais sobre as regras que usam dados atuais para criar condições de segurança.
Selecione um produto em cada seção para saber mais sobre as regras de validação de dados.
Restrições a novos dados
Cloud Firestore
Se você quiser garantir que um documento que contenha um campo específico não seja criado, inclua o campo na condição allow
. Por exemplo, se você quiser negar a criação de qualquer documento que contenha o campo ranking
, você terá de proibi-lo na condição create
.
service cloud.firestore {
match /databases/{database}/documents {
// Disallow
match /cities/{city} {
allow create: if !("ranking" in request.resource.data)
}
}
}
Realtime Database
Se você quiser garantir que os dados que contêm determinados valores não sejam adicionados ao seu banco de dados, inclua esses valores nas regras e bloqueie a gravação delas. Por exemplo, se você quiser negar qualquer gravação que contenha os valores de ranking
, bloqueie as gravações de qualquer documento com os valores de ranking
.
{
"rules": {
// Write is allowed for all paths
".write": true,
// Allows writes only if new data doesn't include a `ranking` child value
".validate": "!newData.hasChild('ranking')
}
}
Cloud Storage
Se você quiser garantir que um arquivo que contém metadados específicos não seja criado, inclua esses metadados na condição allow
. Por exemplo, se quiser negar a criação de qualquer arquivo que contenha metadados de ranking
, bloqueie-os na condição create
.
service firebase.storage {
match /b/{bucket}/o {
match /files/{allFiles=**} {
// Disallow
allow create: if !("ranking" in request.resource.metadata)
}
}
}
Usar dados atuais nas regras de segurança do Firebase
Cloud Firestore
Muitos aplicativos armazenam informações de controle de acesso como campos em documentos no banco de dados. As regras de segurança do Cloud Firestore podem permitir ou negar acesso dinamicamente com base nos dados do documento:
service cloud.firestore {
match /databases/{database}/documents {
// Allow the user to read data if the document has the 'visibility'
// field set to 'public'
match /cities/{city} {
allow read: if resource.data.visibility == 'public';
}
}
}
A variável resource
refere-se ao documento solicitado, e resource.data
é
um mapa de todos os campos e valores armazenados no documento. Para mais informações sobre a variável resource
, consulte a documentação de referência.
Ao gravar dados, pode ser necessário comparar as informações novas com as atuais. Dessa forma, é possível garantir, por exemplo, que um campo não seja alterado, que ele tenha o valor incrementado em apenas um ou que o novo valor esteja pelo menos uma semana no futuro.
Nesse caso, se o conjunto de regras permitir a gravação pendente, a variável request.resource
conterá o estado futuro do documento. Para operações update
que apenas modificam um subconjunto dos campos do documento, a variável request.resource
conterá o estado do documento pendente após a operação. É possível verificar os valores dos campos em request.resource
para evitar atualizações de dados indesejados ou inconsistentes:
service cloud.firestore {
match /databases/{database}/documents {
// Make sure all cities have a positive population and
// the name is not changed
match /cities/{city} {
allow update: if request.resource.data.population > 0
&& request.resource.data.name == resource.data.name;
}
}
}
Realtime Database
No Realtime Database, use regras .validate
para aplicar estruturas de dados e validar o formato e o conteúdo deles. As regras executam regras .validate
depois de verificar se uma regra .write
concede acesso.
As regras .validate
não são aplicadas em cascata. Se qualquer regra de validação falhar em qualquer caminho ou subcaminho, a operação de gravação como um todo será recusada.
Além disso, as definições de validação verificam se há apenas valores não nulos e, em seguida, ignoram qualquer solicitação que exclua dados.
Suponha as seguintes regras .validate
:
{
"rules": {
// write is allowed for all paths
".write": true,
"widget": {
// a valid widget must have attributes "color" and "size"
// allows deleting widgets (since .validate is not applied to delete rules)
".validate": "newData.hasChildren(['color', 'size'])",
"size": {
// the value of "size" must be a number between 0 and 99
".validate": "newData.isNumber() &&
newData.val() >= 0 &&
newData.val() <= 99"
},
"color": {
// the value of "color" must exist as a key in our mythical
// /valid_colors/ index
".validate": "root.child('valid_colors/' + newData.val()).exists()"
}
}
}
}
As solicitações de gravação para um banco de dados que use as regras acima teriam os seguintes resultados:
JavaScript
var ref = db.ref("/widget"); // PERMISSION_DENIED: does not have children color and size ref.set('foo'); // PERMISSION DENIED: does not have child color ref.set({size: 22}); // PERMISSION_DENIED: size is not a number ref.set({ size: 'foo', color: 'red' }); // SUCCESS (assuming 'blue' appears in our colors list) ref.set({ size: 21, color: 'blue'}); // If the record already exists and has a color, this will // succeed, otherwise it will fail since newData.hasChildren(['color', 'size']) // will fail to validate ref.child('size').set(99);
Objective-C
FIRDatabaseReference *ref = [[[FIRDatabase database] reference] child: @"widget"]; // PERMISSION_DENIED: does not have children color and size [ref setValue: @"foo"]; // PERMISSION DENIED: does not have child color [ref setValue: @{ @"size": @"foo" }]; // PERMISSION_DENIED: size is not a number [ref setValue: @{ @"size": @"foo", @"color": @"red" }]; // SUCCESS (assuming 'blue' appears in our colors list) [ref setValue: @{ @"size": @21, @"color": @"blue" }]; // If the record already exists and has a color, this will // succeed, otherwise it will fail since newData.hasChildren(['color', 'size']) // will fail to validate [[ref child:@"size"] setValue: @99];
Swift
var ref = FIRDatabase.database().reference().child("widget") // PERMISSION_DENIED: does not have children color and size ref.setValue("foo") // PERMISSION DENIED: does not have child color ref.setValue(["size": "foo"]) // PERMISSION_DENIED: size is not a number ref.setValue(["size": "foo", "color": "red"]) // SUCCESS (assuming 'blue' appears in our colors list) ref.setValue(["size": 21, "color": "blue"]) // If the record already exists and has a color, this will // succeed, otherwise it will fail since newData.hasChildren(['color', 'size']) // will fail to validate ref.child("size").setValue(99);
Java
FirebaseDatabase database = FirebaseDatabase.getInstance(); DatabaseReference ref = database.getReference("widget"); // PERMISSION_DENIED: does not have children color and size ref.setValue("foo"); // PERMISSION DENIED: does not have child color ref.child("size").setValue(22); // PERMISSION_DENIED: size is not a number Map<String,Object> map = new HashMap<String, Object>(); map.put("size","foo"); map.put("color","red"); ref.setValue(map); // SUCCESS (assuming 'blue' appears in our colors list) map = new HashMap<String, Object>(); map.put("size", 21); map.put("color","blue"); ref.setValue(map); // If the record already exists and has a color, this will // succeed, otherwise it will fail since newData.hasChildren(['color', 'size']) // will fail to validate ref.child("size").setValue(99);
REST
# PERMISSION_DENIED: does not have children color and size curl -X PUT -d 'foo' \ https://docs-examples.firebaseio.com/rest/securing-data/example.json # PERMISSION DENIED: does not have child color curl -X PUT -d '{"size": 22}' \ https://docs-examples.firebaseio.com/rest/securing-data/example.json # PERMISSION_DENIED: size is not a number curl -X PUT -d '{"size": "foo", "color": "red"}' \ https://docs-examples.firebaseio.com/rest/securing-data/example.json # SUCCESS (assuming 'blue' appears in our colors list) curl -X PUT -d '{"size": 21, "color": "blue"}' \ https://docs-examples.firebaseio.com/rest/securing-data/example.json # If the record already exists and has a color, this will # succeed, otherwise it will fail since newData.hasChildren(['color', 'size']) # will fail to validate curl -X PUT -d '99' \ https://docs-examples.firebaseio.com/rest/securing-data/example/size.json
Cloud Storage
Durante a avaliação de regras, é possível também examinar os metadados do arquivo que está sendo modificado, excluído ou transferido por upload ou download. Crie regras complexas e eficazes, como permitir o upload somente de arquivos com um conteúdo específico ou apenas a exclusão de arquivos maiores com um tamanho determinado.
O objeto resource
contém pares de chave-valor com metadados de arquivo exibidos em um objeto do Cloud Storage. Essas propriedades podem ser inspecionadas em solicitações read
ou write
para garantir a integridade dos dados. O objeto resource
verifica os metadados nos arquivos existentes no bucket do Cloud Storage.
service firebase.storage {
match /b/{bucket}/o {
match /images {
match /{allImages=**} {
// Allow reads if a custom 'visibility' field is set to 'public'
allow read: if resource.metadata.visibility == 'public';
}
}
}
}
Também é possível usar o objeto request.resource
em solicitações write
(como uploads, atualizações de metadados e exclusões). O objeto request.resource
recebe metadados do arquivo que será gravado se o write
for permitido.
Use esses dois valores para impedir atualizações não solicitadas ou inconsistentes ou para aplicar restrições de aplicativo, como tipo ou tamanho de arquivo.
service firebase.storage {
match /b/{bucket}/o {
match /images {
// Cascade read to any image type at any path
match /{allImages=**} {
allow read;
}
// Allow write files to the path "images/*", subject to the constraints:
// 1) File is less than 5MB
// 2) Content type is an image
// 3) Uploaded content type matches existing content type
// 4) File name (stored in imageId wildcard variable) is less than 32 characters
match /{imageId} {
allow write: if request.resource.size < 5 * 1024 * 1024
&& request.resource.contentType.matches('image/.*')
&& request.resource.contentType == resource.contentType
&& imageId.size() < 32
}
}
}
}
Uma lista completa de propriedades no objeto resource
está disponível na
documentação de referência.