Adding a Restricted Administration Console to Your Laravel Application

  • April 07, 2016

Welcome to the incredibly popular Easy Laravel 5 companion blog. To celebrate the new edition's release (updated for Laravel 5.5!) use the discount code easteregg to receive 20% off the book or book/video package! » Buy the book

Many applications require a certain level of ongoing monitoring and maintenance beyond the typical code-based improvements. For instance you might wish to add new categories or edit existing names and descriptions, view a comprehensive list of registered users, or keep tabs on content creation and interaction trends. Such features should logically be accessible only by project administrators, yet be conveniently accessible. One effective way to integrate these capabilities is via a restricted web-based administration console. In this post (adapted from my bestselling book, Easy Laravel 5) I'll show you a particularly simple yet effective solution for creating such a console.

Identifying Administrators

There are several third-party packages one can use to add role-based permissions to a Laravel 5 application, including perhaps most notably Entrust. However if your goal is to simply separate typical users from administrators, then a much more simple solution is available. You'll want to add a new column to the users table named something like is_admin. This Boolean column will identify administrators by virtue of being set to true. Go ahead and create the migration now:

$ php artisan make:migration add_is_admin_to_user_table --table=users
Created Migration: 2016_04_07_130041_add_is_admin_to_user_table

Next, open the newly created migration file and modify the up and down methods to look like this:

public function up()
{
    Schema::table('users', function(Blueprint $table)
    {
        $table->boolean('is_admin')->default(false);
    });
}

public function down()
{
    Schema::table('users', function(Blueprint $table)
    {
        $table->dropColumn('is_admin');
    });
}

After saving these changes, run the migration:

$ php artisan migrate
Migrated: 2016_04_07_130041_add_is_admin_to_user_table

After running the migration, all existing users will have their is_admin column set to false (the default as defined in the migration). Therefore to identify one or more users as administrators you'll need to login to your database and set those users' is_admin columns to true. For instance if you're using the mysql client you can login to the client and run the following command:

mysql> update users set is_admin = true where email = 'wj@wjgilmore.com';

Creating the Administration Controllers

Next we'll create an administration controller. In reality you'll likely wind up with several controllers which are collectively identified as being administrative in nature, so you can create a convenient route grouping which places them all under a route prefix and namespace. Create your first such controller by executing the following command:

$ php artisan make:controller admin/UserController
Controller created successfully.

This make:controller command is a bit different from the others you've executed so far throughout the book because we are prefixing the controller name with a directory name. In doing so, a directory named admin was created inside app/Http/Controllers, and inside admin you'll find the UserController.php directory. We'll use this controller to list and manage registered users. Next let's create the route grouping which identifies both the URI prefix and the namespace:

Route::group(['prefix' => 'admin', 'namespace' => 'admin'], function()
{
    Route::resource('user', 'UserController');
});

Note the user of Route::group. This allows you to nest controller inside the definition block without redundantly declaring the prefix and namespace. So for instance at some time in the future you might have three or four administrative controllers. You can follow the same approach used to create the User controller, and then add them to routes.php like this:

Route::group(['prefix' => 'admin', 'namespace' => 'admin'], function()
{
    Route::resource('category', 'CategoryController');
    Route::resource('list', 'ListController');
    Route::resource('product', 'ProductController');
    Route::resource('user', 'UserController');
});

With this route definition in place, create a new directory named admin inside resources/views, and inside it create a directory named user. This will house the views associated with the new administrative User controller. Inside the user directory create a file named index.blade.php and add the following contents to it:

{% raw %}

Registered Users

<ul>
@forelse ($users as $user)

    <li>{{ $user->name  }} ({{ $user->email }})</li>

@empty

    <li>No registered users</li>

@endforelse
</ul>

{% endraw %}

Finally, open the new User controller (app/Http/Controllers/admin/UserController.php) and update the index action to look like this:

public function index()
{
    $users = User::orderBy('created_at', 'desc')->get();
    return view('admin.user.index')->withUsers($users);
}

With these changes in place you should be able to navigate to /admin/user and see a bulleted list of any registered users! Of course, before deploying this to production you'll want to restrict access to only those users identified as administrators. Let's do this next.

Restricting Access to the Administration Console

We want to allow only those users identified as administrators (their users table record's is_admin column is set to true). You might be tempted to make this determination by embedding code such as the following into your controller actions:

if (Auth::user()->is_admin != true) {
    return \Redirect::route('home')->withMessage('Access denied!');
}

Don't do this! This is a job perfectly suited for custom middleware. Let's create a middleware which neatly packages this sort of logic, and then associate that middleware with our administrative controllers:

$ php artisan make:middleware AdminAuthentication
Middleware created successfully.

This command created a new middleware skeleton named AdminAuthentication.php which resides inside app/Http/Middleware. Open this file and update it to look like the following:

namespace App\Http\Middleware;

use Closure;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Http\RedirectResponse;

class AdminAuthentication {

    protected $auth;

    public function __construct(Guard $auth)
    {
        $this->auth = $auth;
    }

    public function handle($request, Closure $next)
    {
        if ($this->auth->check())
        {
            if ($this->auth->user()->is_admin == true)
            {
                return $next($request);
            }
        }

        return new RedirectResponse(url('/'));

    }

}

Most of this should be familiar by now given coverage of authentication and middleware in chapters 5 and 6, respectively, so I won't belabor the changes. Save this file and then open App/Http/Kernel.php and register the middleware inside the $routeMiddleware array:

protected $routeMiddleware = [
    ...
    'admin' => \App\Http\Middleware\AdminAuthentication::class,
];

With the middleware registered, all that remains is to associate the middleware with the route group:

Route::group(
    [
      'prefix' => 'admin', 
      'namespace' => 'admin', 
      'middleware' => 'admin'
    ], function()
    {
        Route::resource('user', 'UserController');
    });

Once you've saved this change to the routes.php file, your administrative controllers will be restricted to administrators!