In our application, we accomplish roles/permissions by looking at a combination of the URI and HTTP Method. We feel this gives us the greatest flexibility.
For example, here is our table structure:
Actions Table
- name
- description
- path
- method (get, post, put, patch, delete)
- recursive (explanation further down)
Roles Table
Role/Action Pivot Table
User/Role Pivot Table
With this structure, the "Roles" act as a grouping mechanism for actions that the user can perform.
A typical action may look something like this:
Name: Administrator
Description: Access to the dashboard.
Path: /admin
Method: GET
Recursive: 0 (false)
This action would be assigned to a Role, which would then be assigned to a user.
If this was the only action the user had, they would only be able to access the "/admin" URI with a GET request.
Explanation of the "recursive" field:
I truly believe this is the secret sauce to our authentication system. It's very simple, but gives tremendous flexibility.
Using the same example as above:
Name: Administrator
Description: Access to the dashboard.
Path: /admin
Method: GET
Recursive: 1 (true)
Now, just by changing the recursive field to true, the user can access any URI under "/admin" recursively.
For example, the user would now be able to access all of the following URIs:
- /admin
- /admin/settings
- /admin/content/1/edit
- /admin/some/other/page/it/does/not/matter/how/far/you/go
You get the idea..
Just another few examples of the flexibility this provides:
Name: Content Administrator
Description: Access to create new content in the dashboard.
Path: /admin/content
Method: POST
Recursive: 0 (false)
Name: Super User
Description: Complete and total access
Path: /
Method: (NULL)
Recursive: 1 (false)
By leaving the method null, they are allowed to perform any HTTP request.
Obviously there is a ton of logic going on under the hood, but I hope this gives you some ideas about how to handle authentication.