dimanche 10 octobre 2021

Is there an access pattern that enables this many-to-many-to-many relationship that can be handled by security rules when using Firestore onSnapshot?

I've been trying to build a system where users can be assigned to groups and groups can be assigned to resources. If a user is a member of a particular group, that user can access all resources shared with that group.

A user can be part of multiple groups and a resource can be shared with multiple groups. For example, a user may be part of the 'admins' and 'development team' groups, and a resource may be shared with the 'marketing' and 'development team' groups.

A db structure and query which successfully handles this is:

<collection>
    [doc]

<users>
    [userId]: {
        groups: [groupId, groupId...]
    }

<groups>
    [groupId]: {
        members: [userId, userId...]
    }

<resources>
    [resourceId]: {
        accessibleBy: [groupId, groupId...]
    }

and the Firestore query:

db.collection('/resources').where("accessibleBy", "array-contains-any", [...aUsersGroups])

This works great. However, where this gets difficult is security rules. I am using onSnapshot listeners and the rule I initially created (below) fails, I assume because it needs to check access to each document based on the 'accessibleBy' field, which would get very computationally expensive when accessing large collections.

 match /resources/{resourceId} {
     allow read: if resource.data.accessibleBy.hasAny(get(/databases/$(database)/documents/users/$(request.auth.uid)).data.groups);
 }

It is worth noting that the above rule does work for individual Firestore get() requests.

Some options I have considered:

  • I have contemplated normalising our data structure by group, but I imagine this would require lots of duplication of data which could become unmanageable.
  • I have also contemplated building a system that just uses get() calls instead of listeners but I do need realtime(ish) updates and this would probably become inefficient.
  • Finally I have contemplated using a nodejs environment but I am not familiar with access patterns using a server and I would still be looking to achieve realtime functionality.

I am willing to only assign users to one group (or perhaps one group, plus default read access), but I do need the functionality to share resources across multiple groups.

Firestore may not be the answer to my problems here but I thought I'd ask the community before I look elsewhere. Thank you in advance! :)

Aucun commentaire:

Enregistrer un commentaire