The question came up in a somewhat unrelated discussion, about the RavenDB authorization bundle usage:
I have an 'Account' service which is responsible for managing all things 'user'.
I have a 'Messaging' service which is responsible for all things 'messaging' i.e. wall posts, conversations etc.
My question is this:
- Should the account service store the master User with Roles and Permissions - when it is asked for a user it can send back a dto with the roles and permissions (could get chunky)
- Should the Messaging Service maintain it's own copy of a User - with it's own set of roles and permissions?
I wasn’t sure what to answer, because a lot depended on the actual physical infrastructure of the system. But after some back & forth, it turned out that those were true services, in other words, they were independent from one another and each had its own data store.
That completely ruled out the first possibility, we don’t want to have to rely on another service for something that is as central for our service as authorization. The other option, of having each service (there are currently 5, all total) maintain their own users, is fraught with the potential for disaster.
Instead, a better option is to simply replicate the relevant parts from the Account’s service database to the related services. The authorization bundle record information about users, roles & permissions, that allows us to create the following data storage scheme for the Account database. Actually, we are talking about two different databases in the Account database instance:
- Accounts – All the application specific account information
- Permissions – All the authorization information
We setup RavenDB replication from the Account.Permissions database to each of the services databases, that means that any change to permission will be replicated to all the related databases.
For each service, we treat the authorization information as usual, and we get cross service, background replicated, fully distributed authorization system that can make authorization decisions without touching any external data source.
Let us take the example of viewing a message:
- Jane sends a message on Joe’s wall (which should only be visible to Joe’s friends). The new message is written to the Messages database.
- Drew then befriends Joe. That means that we setup the friendships on the Accounts database and the permissions on the Permissions database.
- The information on the Permissions database then replicates to the Messages database.
- The next query to the Messages database will make the authorization decisions locally, against its own copy, but it will get the new permissions and show Jane’s message to Drew.
That is quite elegant, even if I say so myself.