Firebase Firestore security rules - read all nested docs based on resource (but it's null)

别说谁变了你拦得住时间么 提交于 2021-02-11 13:05:35

问题


I think I'm doing something wrong but I can't figure which part... Thanks for all the clarification I can get.

So I have a collection named Bases that looks like this:

{
  "id1": {
    "name": "My base 1",
    "roles": {
      "idUser_123": {
        "name": "John"
      }
    }
  },
  "id2": {
    "name": "My base 2",
    "roles": {
      "idUser_456": {
        "name": "Jane"
      }
    }
  }
}

idUser_123 log in and want to access his collection. So I do: db.collection('bases').get()

And I use a match rule to make sure John is not reading Jane's bases. And that's where I think I'm wrong cause I'm using rule for filter purpose.

match /bases/{document=**}{
    allow read: if request.auth.uid in resource.data.roles;
}

Which failed because resource is null... I tried to do this:

match /bases/{baseId}{
    allow read: if request.auth.uid in resource.data.roles;
}

This work in the simulator when requesting specific document but fails when I'm get() without baseId from client - cause I want them all.

So how am I supposed to handle this very basic use case (IMO)?

I can't put all user's baseId in user.token as it'll be over 1000 bytes quite fast.

I can make an other collection Roles to create a relation between a baseId and my user but that's seems overengineered for a simple use case.

Or I can make the request on a server and filter where("roles", "has", user.uid) ? Defeat the purpose of fetching data on client side very very quickly in my opinion...

Any recommendation on how to address this will be gladly appreciated! Thanks a lot :)


回答1:


There are two problems here.

Firstly, your query is demanding to receive all of the documents in bases, but your rules do not allow anyone to simply receive all documents. It's important to realize that Firestore security rules are not filters. They do not strip documnts from a query - this actually does not scale. If a rule puts requirements on who can query certain documents based on their contents, the query will have to use a filter that matches what the rule requires.

Secondly, your data isn't structured in a way that the client can perform a filter of only certain documents based on the user's UID. Firestore doesn't have queries that can check for the existence of a map field. It can only check for map values. You might want to restructure your document data so that the client can actually perform a query with a filter to get only the documents for the current user.

If roles was an array of UIDs:

  "id1": {
    "name": "My base 1",
    "roles": [ "idUser_123" ]
  },

Then the client could filter on that field:

firebase.firestore()
    .collection("bases")
    .where("roles", "array-contains", uid)

And you could enforce the use of that filter in rules:

match /bases/{document=**} {
    allow read: if request.auth.uid in resource.data.roles;
}

But you might want to do something different.



来源:https://stackoverflow.com/questions/65107041/firebase-firestore-security-rules-read-all-nested-docs-based-on-resource-but

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!