Security rules for updates in Firestore

2019-06-14 06:35发布

问题:

In the realtime database when an update is called on a single value the security rules will evaluate the values present in the database if it is not specified within the request.

In Firestore we have to create rules for the data already present in Firestore resource.data, or the data in the request request.resource.data.

This causes you to have to replicate your security rules with an or condition to check for present data so that an individual value can be updated.

What is the best way to structure security rules to specify a single condition for each of a set of datas values while still allowing an update on an individual piece of that data?

match /subscriptions/{uid} {
    allow read: if request.auth.uid == uid;
    allow write: if request.auth.uid == uid                     
        && request.resource.data.keys().hasAll(['allowedTerminals', 'activeTerminals'])
        && request.resource.data.allowedTerminals is int && request.resource.data.allowedTerminals > 0
        && request.resource.data.activeTerminals is int;
}

Given this security rule I could successfully create a new subscription when I initially provide both activeTerminal and allowedTerminal values, but if I wanted to update the activeTerminal value I would have to provide the allowedTerminal value as well or the update would return a permission denied error.

回答1:

The behavior between the Realtime Database and Firestore is actually very similar:

data == resource.data             // data in the database
newData == request.resource.data  // data in the incoming request

The main difference is that Firestore offers granular operations:

allow get, list; // same as allow read;
allow create, update, delete; // same as allow write;

It's likely that you'll want to have separate rules for create, update, and delete:

allow create: if isMyCustomObject(request.resource.data);
allow update: if isUpdateToMyCustomObject(request.resource.data);
allow delete: if ...

You can read more about this in the docs (sorry that part got pushed so far down!)