I am new to security rules. I have to write security rule to prevent a user to update a document except one field.
lets say i have a doc
{ field1 : one, field2 : two, field3 : three, . . . fieldn : n }
the user logged in should be able to update only field2. using firestore security rules.
If you need some value (or combination of values) to be unique, you need to create a node that contains that value (or combination) as its key. If you need to guarantee that multiple values (or combinations) are unique, you'll need multiple of such nodes.
Edit and update your rulesOpen the Firebase console and select your project. Then, select Realtime Database, Cloud Firestore or Storage from the product navigation, then click Rules to navigate to the Rules editor. Edit your rules directly in the editor.
A DocumentSnapshot is an immutable representation for a document in a Firestore database. The data can be extracted with [data()] or [get(fieldPath)] to get a specific field. For a DocumentSnapshot that points to a non-existing document, any data access will return 'undefined'.
There is no explicit way in security rules to validate the update that is happening. But what you can do is validate the data in the document before and after the write operation. By comparing those two, and by knowing what fields the document can contain, you can ensure that only specific fields can be updated.
I often use this little helper function in my security rules:
function isUnmodified(key) {
return request.resource.data[key] == resource.data[key]
}
As its name implies, it ensures that a certain key/field is not modified in this write request. For example, this rule then only allows a user to update their profile document, as long as they don't modify the name
field (unless they're an admin):
allow update: if isAdmin(request) ||
(request.auth.uid == uid && isUnmodified(request, resource, 'name'));
I also have this helper function, which checks whether a specific field exists:
function isNotExisting(key) {
return !(key in request.resource.data) && (!exists(resource) || !(key in resource.data));
}
This is important, because sometimes you want to allow a field to be only written once, or only allow it to be updated if it already exists. Sometimes I use isNotExisting
for that, but I find myself more these days using the more granular actions (create
, update
) over the aggregate write
rule.
Finally, you can require certain fields, as in this creation rule:
allow create: if request.auth.uid == uid &&
request.resource.data.keys().hasOnly(['lastIndex', 'lastUpdated']) &&
request.resource.data.keys().hasAll(['lastIndex', 'lastUpdated'])
So a user can only create a profile document if they specify lastIndex
and lastUpdated
fields. If they specify any additional fields, or specify fewer fields, the creation will be rejected.
Now with this knowledge, we can go back to your requirement, and see how to implement it. As said before, you will need to make a statement on each individual field, without having a wildcard in there. So if your document has three fields (field1
, field2
, and field3
), which must all exist, and the user can only update field2
, that'd be something like:
allow update: if request.resource.data.keys().hasAll(['field1', 'field2', 'field2']) &&
isUnmodified('field1')) && isUnmodified('field3'));
There may nowadays be a shorter way to do this by using the set and map diff operations that are shown here: https://firebase.google.com/support/release-notes/security-rules#february_13_2020 like:
// This rule only allows updates where "a" is the only field affected allow update: if request.resource.data.diff(resource.data).affectedKeys().hasOnly(["a"]);
If you prefer the method of specifying which fields can be editable, I found a section in this tutorial to be helpful: Intermediate topics in Firebase Security Rules - Firecasts
// Make sure the request has only the specified allowed fields
function editingOnlyAllowedFields(allowedFields) {
let editedKeys = request.resource.data.diff(resource.data).affectedKeys();
return editedKeys.hasOnly(allowedFields);
}
// Then, you can specify which fields you want to be updatable
allow update: editingOnlyAllowedFields(["field1", "field2"]);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With