Configuring Permissions and Sharing Realms across Multiple Users
Asked Answered
P

1

5

I'm using Realm Swift and the Realm Object Server as the storage solution for an app I am working on. I could use a traditional server with a relational database, but I really don't need the server to do any real work. The only backend that I really need is just storage and data syncing. Realm seems to provide exactly what I want.

So far, I have a working example of a realm. The problem that I have started running into is access control. I feel like I may have a fundamental misunderstanding of what Realm can provide me, and there are not a ton of fantastic resources out there. The Realm documentation is pretty detailed, but it doesn't have the best working examples.

My app will be used to track teams from an available set of players. The set of players will be relatively constant and unchanging. The teams, however, will change frequently. With this in mind, I had the following idea of my Realm setup:

  • A single Realm containing the set of all players: /Players. Every user should have read access to this realm but only admins should have write and manage.
  • A single Realm for each user of the application /~/MyRoster. This realm should be read/write by that user. I think that the user should be able to grant another user temporary read/write access to their realm as well.
  • Multiple users should be able to form a team wherein they can read (and potentially write) all team users' rosters.

Does this sound like an acceptable use of the Realm backend? How should I manage the central shared data pool? Should I just create a /~/MyRoster realm for a user as soon as they register? How could I configure the permissions the way that I want them? To me, the permission structure seems very strange. It seems like I can use the PermissionOffer/PremissionOfferResponse constructs to achieve the Realm sharing that I want.

Any help would be greatly appreciated.

Phenolphthalein answered 22/6, 2017 at 17:8 Comment(2)
Just a quick question: when you say you plan on using Realm as a backend, do you mean to use it for data persistence or as a real server? Because as I understand Realm, it's not a real server-type backend.Harm
@ScottChow, Realm will be my storage solution, but the Object Server actually provides all the server-side functionality that I really need for the backend -- user authentication and communication with the Realm storage on the server.Phenolphthalein
W
7

Thanks for the detailed write-up. Your proposed architecture seems like a good fit. Here is what I would recommend:

  1. For the global /Players Realm, I would create that within development. Today this is a bit clunky in that you have to use a client SDK to open the Realm as an admin user (because only admin users can create Realms outside of their scope /~/ directory). You could create a code path in your app that if you sign in as an admin, this opens the /Players Realm and then apply a permission change to that Realm:
let permission = SyncPermissionValue(realmPath: "/Players",
                                 userID: "*", // To apply to all users
                                 accessLevel: .read)
user.applyPermission(permission) { error in
  if let error = error {
    // handle error
    return
  }
  // permission was successfully applied
}

This code path doesn't need to be run more than once. Our plan is to add this kind of functionality into the browser in the dashboard so you can just manually create a global Realm and adjust permissions without using a client SDK.

  1. For the user-specific Realms, you do not need to create them immediately, because the Realms will get lazily created when the user eventually needs it. What I mean is that Realm is setup such that you can open a Realm on the client synchronously (enabling the offline-first capability), and then after the first creation when the client syncs to the server, will the server actually become aware and also create the Realm within it. Thus you client code just needs to be setup to open the Realm at /~/MyRoster when necessary.

    As for granting permissions to other users, this would use the Swift access control APIs to apply a permission change to the user's Realm and grant access to the other user. This can happen dynamically, such that the user can grant, then revoke the permission as needed.

  2. For the third part with regards to groups, I would create another global Realm, /Group, that has read/write access to all users which holds the representation of the groups. For example you could have a Group object which contains a list property linking to User objects, with 1 User per user within your application. This way every user could make changes to the Realm to represent the groups he/she is part of.

    You could setup a Realm Function to listen to changes to the /Group Realm such that when a user is added to a group or removed, the function would trigger the necessary permission change to the various Realms in the group.

    Now if your are concerned about access control to the /Group Realm, you could instead, setup a Realm Function that uses an admin user to apply changes to /Groups, listening to a user-specific Realm /~/MyRequests where a user could write an object to this Realm which would trigger the function to make a change to the group Realm. In this manner you could prevent unauthorized requests, and keep the /Group Realm as read-only for all users but admins.

Weatherboarding answered 27/6, 2017 at 22:19 Comment(6)
Thanks for the great write up! Some follow up: 1) is it likely to see performance or storage impacts by having a realm for each individual user? 2) Is there any config that I need to do to enable offline-first? I haven't investigated that capability just yet -- just been relying on the Object Server. 3) For /Group, are you thinking the realm would contain an object Group maybe looking like {id: 1, desc: "Group 1", Users: [Nick, Adam]} wherein Users is a List<User>? That should also grant the ability for 1 User to be on many Groups. Thanks again for stopping by and helping out!Phenolphthalein
1) No obvious performance impact. You can think of a Realm is like a document is to MongoDB, the server is designed to manage lots of them. 2) No config, if you open a Realm (with synchronous API, we recently added an async variant to download the data from the server first) it creates a local copy immediately. This is why we have a tilde character for Realm URLs, /~/myRealm, because if you open offline you might not even know yet the user ID, so this is short hand for that. 3) yes that would work and you could use a function to listen for changes and apply permissions in response.Weatherboarding
Thanks, you've really helped me out here. I also just found the Tech Notes section of the realm docs which details an architecture similar to what I'm envisioning. That also lead me to the demos repo which will be a good reference. It's awesome to see you guys are actively supporting your platform on here. Here's to hoping realm will serve me well!Phenolphthalein
No problem and glad to hear that!Weatherboarding
@NickAlexander would you mind sharing a link to those tech notes?Biblicist
Thanks Adam. Following up on this, I could use some clarifications: 1- Most apps will need a 'User' object to hold user data (customer payment status, sessions data, statistics and such) what's the best Realm architecture to support that? From reading your reply, it seems that the best option is creating a global realm( similarly to the /Group repository in your reply) and granting read/write access to all user. This creates a security issue (from you reply) and you're recommending Realm Functions- 2- Realm functions? realm dashboard? is that really a thing? only found old docs in JapaneseDoak

© 2022 - 2024 — McMap. All rights reserved.