User authentication is a huge part of web applications, with it being necessary in the majority of cases, on top of which, it’s usually the first part of any system that a developer will approach, or at least it should be. Laravel is a powerful, easy to use framework that provides you with the basic tools to create a simple ACL to suit your needs.
I am aware that there are many packages for Laravel that offer this functionality, but I find them often to be more complicated than necessary. In this article I will detail how to create a simple yet highly customisable ACL using the basic tools that Laravel ships with.
Lets start at the beginning shall we.
Laravels routing system is one of the best that I have seen, easily allowing you to create resourceful routes, restful routes or even just plain routes. An overlooked feature of this is the naming of routes. As a standard practise, I name every route that I create when working with Laravel. Take the below extract from a project I am working on, as an example.
You’ll see here that we have three different routes, that provide some base functionality. I’m not going to go into detail about what each of these routes actually does, because for our purpose here, that isn’t important.
Each of these routes has a name attribute (as), meaning that I have a way to refer to each individual route with ease, regardless of the URI parameters present in the request. Providing that you’ve given your routes sensible and unique names, you already have the base permissions in place.
Now that we have our routes with their individual names, we need a way of assigning users certain permissions. Again, for the purpose of this article I’m not going to go into detail regarding the user side of this system as the assumption is that you already have your user model and user tables setup.
ACLs often have two main components, they are groups and permissions. A user will belong to a group or multiple groups, and multiple permissions will belong to a group, allowing easy permission assignment without adding an individual assignment for each permission, for each user.
To achieve this, we’re going to create four simple tables. One for groups, one for permissions, one for user to group association and one for group to permission association. To do this I’m going to use the Laravel migration functionality, where the assumption is that you’re familiar with this. If you’re not, check out the documentation regarding migrations and schema building.
and finally, you run all of these migrations like so.
Using the database.
Now that we’ve created and ran our migrations, we need a way to access these tables. For this article, I’ll be using Eloquent, the default Laravel ORM.
Lets start with our AclGroup model.
It’s a fairly standard model as you’ll see. You’ll also need to add the corresponding relationship to your user model.
Now lets add the AclPermission model.
For most of you, this model will make total sense, but there will be some of you that aren’t familiar with the getKey() method in Eloquent models. For our purpose here, this basically allows us to identify the model within a collection, by the ident, which you will see in the next step.
We’ve got the database setup, we’ve got a way to access this information, now all we need to do is implement it. At this point you may be wondering what route names had to do with anything, but hold on just a bit longer, because you’re about to find out.
The simplest way to limit access to certain pages based on the user permissions would be to use a filter, which we can add to our routes, like so.
Here I’ve added the filter under the name ‘acl.permitted’ and added the filter to the route via the before attribute, but you could group functionality to be filtered quite easily. You’ll also notice that I have added the auth filter to the route, to make sure that the user is logged in.
Our AclPermittedFilter class can be created anywhere, as long as Laravel can see it (composer autoload is the best option).
There you go, now when your user tries to access /user/supersecret, unless they belong to a group that has the user.supersecret permission, they can’t see the page.
I appreciate that there are sometimes other cases where extra permissions will need to be checked, but this system doesn’t limit you to route names. You could even write a helper functional to do a check from within the controller, which essentially runs the last half of the AclPermittedFilter@filter method.
I hope you guys enjoyed reading this as much as I enjoyed writing it. Ciao.