问题
I'm setting up my Firestore security rules, but run against one issue wherein I want to limit updating only one specific field within a document by using the hasOnly function. The problem is that I keep getting 'denied' results using the simulator. I'm surely doing something simple wrong... I'm trying to prevent that somebody could update other fields in the document than update_requested_time
, but allow them to update this particular field.
When using the example from the Firestore documentation on hasOnly() — ['a', 'b'].hasOnly(['b', 'a']) == true
— the rule returns true. But when using my own it does not, by that I assume I'm getting something wrong in the part of request.resource.data.keys()
.
The specific rule targeting fields in a specific scenario:
match /scenarios/{scenario} {
allow read: if true;
allow update: if request.auth.uid != null
&& request.resource.data.keys().hasOnly(['update_requested_time']) == true;
The simulator request I'm sending (update with authentication):
{"__name__":"/databases/(default)/documents/scenarios/test1","data":{"update_requested_time":"2019-02-05T11:00:00.000Z"}}
My complete rules:
service cloud.firestore {
match /databases/{database}/documents {
match /scenarios/{scenario} {
allow read: if true;
allow update: if request.auth.uid != null
&& request.resource.data.keys().hasOnly(['update_requested_time']) == true;
match /comments/{comment} {
allow read: if true;
allow create: if request.auth.uid != null;
allow delete,update: if request.auth.uid != null && request.auth.uid == resource.data.user;
}
match /outputs/{tile} {
allow read: if true;
}
match /mutations/{tile} {
allow read: if true;
allow create,update: if request.auth.uid != null;
}
}
match /users/{user} {
allow read: if true;
allow update: if request.auth.uid != null && request.auth.uid == user;
}
}
}
screenshot of firestore rules + simulator
回答1:
request.resource.data
doesn't contain the request data itself, but it rather contains the new version of the resource after the write operation. Therefore the check failed.
Firestore documentation on request.resource
:
The new resource value, present on write requests only.
回答2:
Maybe I'm misreading this, but isn't a solution to have your rule do a deep comparison between request.data
and request.resource.data
to confirm that only the one field changed?
Maybe there is a cleaner way, but what about:
import _ from "lodash";
service cloud.firestore {
match /databases/{database}/documents {
function onlyRequestTimeChanged(currValue, newValue) {
let newCopy = _.cloneDeep(newValue)
newCopy.update_requested_time = currValue.update_requested_time
return _.isEqual(currValue, newCopy)
}
match /scenarios/{scenario} {
allow read: if true;
allow update: if onlyRequestTimeChanged(request.resource,data, request.data)
// ...
}
回答3:
Looks like the right way to do this now is
request.resource.data.diff(resource.data).affectedKeys().hasOnly(["update_requested_time"])
Found from this conversation
来源:https://stackoverflow.com/questions/54504528/firestore-security-rules-using-hasonly-on-a-request-to-check-if-only-a-specific