Building a basic admin panel using Laravel (3) – Authorization

This is the last part of a blog series on building a basic admin panel. Although there are many admin packages available, including Laravel’s own Spark package, we experienced that it’s also very easy to an admin panel yourself.

Especially for new projects that only need a limited set of admin functionality, the Laravel framework itself has enough features to quickly build a basic admin panel. The main advantages: you know every detail of the admin panel and once the project is growing and more functionality is required, it can be easily extended.

We defined three major topics that are found in all admin panels. We started with the authentication of users (part 1) and continued with basic CRUD operation (part 2). In this third part the focus is on authorization. In an admin panel there are often users with different roles. Each user role may have access to different parts of the admin panel and is allowed to perform specific actions.

Authorization: manage the roles and privileges of users

User roles and privileges

There are several options to define user roles and privileges in a Laravel application. It depends a bit on the specific situation and your personal preferences which method is best. We often use middleware, policies and form requests in our web apps to limit the access of users to parts of the admin panel.

Middleware

With middleware we define which routes are available for groups of users.

By default, there’s the ‘auth’ middleware that determines whether a user is logged in to the admin panel. Usually, in an administration panel there are users with different roles. Let’s assume we have two user roles: ‘admin’ and ‘employee’. Admin users have access to the whole panel, while employees only have access to parts of the panel, for example to an overview of tasks that need to be executed.

To arrange such a setup, we start with extending the users table via a migration. We add an additional column role_id and fill it with a 1 for admins, and 2 for employees. Next, we create the middleware:

php artisan make:middleware Admin

This command creates an Admin.php file in the App/Http/Middleware directory with some boilerplate code. Now, adjust the handle method and include the following code (modified code in blue):

public function handle($request, Closure $next)
{
    if (Auth::guest()) {
        return redirect(route('login'));
    }

    if (Auth::user()->role_id > 1) {
        return redirect(route('home'))->with('message','Access denied.');
    }

    return $next($request);
}

Next, we have to register the new middleware in the App/Http/Kernel.php. Add the new middleware to the route middleware group:

protected $routeMiddleware = [
    //default middleware
    ‘admin’ => \App\Http\Middleware\Admin
];

Now, you can use the ‘admin’ middleware, for example in your route file, or in the construct methods of your controller.

Policies

Another way to setup user privileges is by using policies. For example, a user is allowed to update a blog post, but only those blog posts that are written by the user himself. A policy is a good option to manage this. Start by creating the policy via the command line:

php artisan make:policy BlogPolicy --model=Blog

Next, go the AuthServiceProvider and register the policy:

protected $policies = [
    Blog::class => \App\Policies\BlogPolicy
];

Now it’s time to define the logic of the policy. The BlogPolicy already has a view, update, delete and create method. In this example, a user is only allowed to update its own blog posts, so we fill the the ‘update’ method:

public function update(User $user, Blog $blog) {
    return $blog->user_id === $user->id;
}

Only in cases where the user_id associated with the blog equals the id of the currently logged in user the policy will return true. The policy is now ready for use, for example in combination with the ‘can’ middleware in your routes file:

Route::patch(‘blog/{blog}’, ‘BlogController@update’)->middleware(‘can:update,blog’);

‘update’ corresponds to the name of the method in the BlogPolicy. An \App\Blog instance is passed to the policy, because implicit route model binding is used in the definition of the route.

When the user tries to update a blog that’s not his own, a 403 exception is thrown.

Form requests

A third option to restrict user actions is by using form requests. We often use form requests to validate a form: the rules method specifies the validation logic for each of the form fields, and an optional messages method can be used for custom error messages (More on the validation of forms using form requests can be found here).

However, form requests have an additional authorize method that can be used to determine whether the user is allowed to perform the request. Instead of just returning ‘true’ you can write more complex logic.
The individual items (form fields) of the request can be accessed by $this->request->get(‘name_of_field’). When using route model binding (for example in the update blog example above), the model can be accessed via $this->route()->blog. Write your own authorization logic and make sure the authorize method returns true or false.

Which authorization method to choose?

There are no strict rules on when to use middleware, policies (which are actually often used in combination with the ‘can’ middleware) or form requests for authorization. Which method you choose likely depends on your personal preferences. We use the following guidelines:

Does access needs to be arranged on the route level and depends on general parameter, like user role, or time of year? Then we use middleware.

Does a user have access to a route, but only in specific cases, e.g. to update only those items that are created by the user himself? And do we need this logic at several places in our code? Then we use policies. Also for routes where you don’t have a form request (which is often the case for a get request) a policy is often a good choice.

In other cases we use the authorize methods of form requests.

Extend your admin panel

We now have the basics of every admin panel, and are ready to extend it with all the functionality that’s needed. Of course, each web app and corresponding admin panel has its own specifications. This blog post is an attempt to summarize those parts that we use in almost every admin panel we have built. Feel free to use and customize them according to your needs.


Mijn Twitter profiel Mijn Facebook profiel
Leonie Derendorp Webdeveloper and co-owner of PLint-sites in Sittard, The Netherlands. I love to create complex webapplications using Laravel! Latest post
Building a basic admin panel using Laravel (3) - Authorization

Leave a Reply

Your email address will not be published. Required fields are marked *