There are different approaches to managing roles and permissions on a project, ranging from very simple hardcoded checks to fully adjustable database based solutions.
I wanted to build something in between - a configuration based system, where the roles and permissions would be stored in config files, while users would have roles stored against their accounts in database.
The reason config based roles worked on this particular project was that it offered the right amount of complexity, flexibility and control.
Database based roles and permissions systems are great, they offer a lot of flexibility and freedom, but are a bit harder to control, especially to control and revert changes.
Fully coded alternative gives the opposite - 100% control, but very little operational flexibility - every change requires a code change, new release. Defining complex rules can also easily become mess, as it tends to scatter the logic to different places.
Config based is somewhere in the middle - roles and permissions definitions are controlled in code, at a single place, and it also offers all the complexity to support all different scenarios - all while some operational flexibility is still preserved.
I am going to explain the basic idea here, showing all the code here on the blog would be a bit impractical, but you can definitely check it in a gist I published.
1) create an extension that loads your config files
In my case this was part of Symfony 3 project, so it’s a standard Symfony bundle and it simply loads given config files.
2) create roles and permissions config files with format that matches your needs
I had some specific project requirements, I needed to control CRUD access to entities, control access to various routes, support role hierarchy/inheritance and also group permissions into logical chunks in an API application.
An example of what I came up with:
1 2 3 4 5 6 7 8 9 10
auth: roles: ROLE_USER: - login - dashboard_everyone - statistics ROLE_FRONT_DESK: - ROLE_USER - manage_users
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
auth: permissions: login: # A route name users_get_current: - read # An entity, this gives read-only access Record: - read dashboard_everyone: # Route names again reporting.device: - read reporting.system.status: - read statistics: # Route name again statistics.daily: - read manage_users: # Full access to an entity User: - read - create - update - delete
3) parse the roles and permissions config files into a structure that is useful for you
I created a simple parser that takes the arrays coming from the yaml files into flat arrays of all roles and permissions for given user.
4) use security voters to give/deny access to various operations in your application
Here we can use the very useful Symfony Security Voter mechanism to vote on whether we want to give/reject access to a particular user/operation combination.
Examples of use, this is taken from a REST API controller:
1 2 3
$this->denyAccessUnlessGranted('update', $entity); $this->denyAccessUnlessGranted('read', $this->routeName); // ... you can add more types of voters and mechanisms and use them similarly
Again, here is the whole source code roughly taken from a Symfony 3 project.
I wish you happy coding and no security breaches!