Access parent documents field in Firestore rules

2019-03-16 09:49发布

问题:

I'm implementing a recipe book in Firestore where every user is able to see all the recipes all users created but only the original author of the recipe is allowed to edit or delete the recipe. Any user is also allowed to create a new recipe.

My problem is that I am unable to setup the permissions a subcollection to "listen" on a field of the subcollections parentdocument.

Each recipe document contains three things. A field called name where the name of the recipe is stored, a field called creatorUID where the request.auth.uid of the creators uid is stored and a subcollection called ingredients containing documents with some random fields.

service cloud.firestore {
  match /databases/{database}/documents {

    function isSignedIn() {
      return request.auth != null;
    }

    match /ListOfRecipes/{recipe} {
        allow read, create: if isSignedIn();
        allow update, delete: if resource.data.creatorUID == request.auth.uid;

        match /{list=**} {
            allow read: if isSignedIn();
            // Should return true if recipe.creatorUID has same value as request.auth.uid
            allow write: if recipe.creatorUID == request.auth.uid;
        }
    }
  }
}

The problem is that with these rules it only works to create the recipe document. The subcollection and it's documents are not created since the db says

FirebaseError: [code=permission-denied]: Missing or insufficient permissions. FirebaseError: Missing or insufficient permissions.

The calls is made from Angular client and it's official library.

回答1:

Rules don't cascade, so you'll need to perform whatever checks you need for the document being captured by the Rules.

Generally speaking, {x=**} rules are more often a mistake and the usage of =** only for extremely specific use cases.

From your question, I'm assuming your data mode is something like this:

/ListofRecipes/{recipe_document}/List/{list_document}

In this case, you'll need your Rules to be configured something like this:

service cloud.firestore {
  match /databases/{database}/documents {

    function isSignedIn() {
      return request.auth != null;
    }

    match /ListOfRecipes/{recipe} {
        allow read, create: if isSignedIn();
        allow update, delete: if resource.data.creatorUID == request.auth.uid;

        function recipeData() {
            return get(/databases/$(database)/documents/ListOfRecipes/$(recipe)).data
        }

        match /List/{list} {
            allow read: if isSignedIn();
            allow write: if recipeData().creatorUID == request.auth.uid;
        }
    }
  }
}