How I sync front-end and back-end permissions in single page app
Permissions are hard. Ensuring the javascript front-end of your application is working with the same set of permissions for a given entity as the backend is even harder. The first step towards madness is trying to code the business rules that grant/remove permissions in the frontend. This is opinion not fact. Some people may have managed to do this successfully but I’ve never met them. I like to manage permissions as follows:
Step 1 - Enumerate the permissions
For each entity type in your system define an Enum that encapsulates all the possible permissions. Namespace your permissions. Choose good names.
Step 2 - Centralize the permissions business logic
For each entity type in your system define a Permissions Class that has a get_permissions(entity) class method on it
Step 3 - Check permissions on server-side using set membership
Checking for permissions is now a case of calling the get_permissions() method and testing for the required permission or permissions within the permissions set.
Step 4 - Serialize the permissions along with the rest of entity on the way out
Wherever you serialize the entity in REST responses, add a generated field called permissions that contains the list of permissions. If you are using Django REST Framework you can use method serializer fields to dynamically call get_permissions() and then mix this into a base serializer class.
The serialized entity will now look like:
Step 5 - Use javascript Array methods to check permissions in frontend
Use the new Array methods in ES6 to check permissions. We could use Maps, but they don’t serialize to/from json nicely so I find Arrays work best.
Step 6 - Improvements
- Automatically generate the javascript permissions constants from the enum classes to keep them in sync.
- Cache the entities on the server for the lifetime of the request if they are expensive to generate