Firestore Security Rules - How can I check that a field is/isn't being modified?

前端 未结 9 603
孤城傲影
孤城傲影 2020-11-29 07:24

For the life of me, I cannot understand why the following is resulting in a false for allowing writes. Assume my users collection is empty to start

相关标签:
9条回答
  • 2020-11-29 08:16

    Here's a function that doesn't trigger security rule errors like "Property name is undefined on object".

    Features/properties:

    • If neither the request or the existing resource contains the field, allow the update.
    • If the existing resource contains the field, but the user doesn't supply it, allow the update.
    • If the existing resource does not contain the field, and the user supplies it, deny the update.
    • If the existing resource contains the field, and the user supplies it with the same value, allow the update. If they're not equal, deny the update.
    function notUpdated(key) {
      return !(key in request.resource.data)
             || (
               (key in resource.data)
               && request.resource.data[key] == resource.data[key]
             );
    }
    

    Explanation

    1: If the field isn't present on request.resource.data, it means that the field isn't present on the request nor on the existing resource. (Remember that request.resource.data represents the resource after a successful write operation, i.e. the "future" document.) If the field doesn't exist anywhere, allow the write.

    2: If the field does exist on either the incoming resource or the existing resource, we need to do another check. First, check if the field is present on the existing resource. If it doesn't, the update is denied. If it does, continue to check if the request field is equal to the existing field. If they're equal, allow the write. At this point it's impossible for request.resource.data[field] to trigger a reference error; if the field is present on resource.data, it's present on request.resource.data as well.

    0 讨论(0)
  • 2020-11-29 08:20

    The solution of Tom Bailey (https://stackoverflow.com/a/48177722/5727205) did look promising.

    But in my case I needed to prevent a field from being edited, and could have the case, that the field simply does not exist on the existing data. Thereby I added a check if the field exists.

    This solution does check two checks:

    1. If the field is not in request and non in the existing data (equals field not modified)
    2. or request and existing data are the same (equals field not modified)
     function isNotUpdatingField(fieldName) {
       return
         ( !(fieldName in request.resource.data) && !(fieldName in resource.data) ) || 
         request.resource.data[fieldName] == resource.data[fieldName];
    }
    
    0 讨论(0)
  • 2020-11-29 08:22

    Your rules will be a lot more readable and maintainable if you create a custom function to check for updates. For example:

    service cloud.firestore {
      match /databases/{database}/documents {
        function isUpdatingField(fieldName) {
          return (!(fieldName in resource.data) && fieldName in request.resource.data) || resource.data[fieldName] != request.resource.data[fieldName];
        }
    
        match /users/{userId} {
          // Read rules here ...
          allow write: if !isUpdatingField("role") && !isUpdatingField("adminOnlyAttribute");
        }
      }
    }
    
    0 讨论(0)
提交回复
热议问题