Having set up the roles and permissions all that remains is to enforce the permissions. There are a number of ways of doing this, it can be done in the constructor method of the controller for example. The more popular and straightforward way is to add permissions to routes in web.php.
The term middleware is a broad term that can mean different things in different contexts but in the context of a Web Application Framework it generally refers to those components that are involved in processing the HTTP requests before they are sent to the MVC aspects of your application. Middleware is often concerned with filtering the HTTP traffic so that only those requests that should be allowed through are allowed through or ensuring that requests are directed to the correct place. Middleware can also be involved in improving the performance of the system through caching or other mechanisms.
From this, it can be seen that middleware is clearly the right area to handle security. Laravel comes with its own built-in basic level Authentication middleware which we used to allow users login at the beginning of this section. Spatie Laravel-permission builds on this by adding three additional middleware classes, RoleMiddleware, PermissionMiddleware, RoleOrPermissionMiddleware. To enable these add the following three lines to the app\Http\Kernel.php file
'role' => \Spatie\Permission\Middlewares\RoleMiddleware::class, 'permission' => \Spatie\Permission\Middlewares\PermissionMiddleware::class, 'role_or_permission' => \Spatie\Permission\Middlewares\RoleOrPermissionMiddleware::class,
These appear as follows in my Kernel.php file
Before I can I assign these permissions to Routes I need to be sure I know which routes I'm talking about. Many of the routes in my application are defined by lines like Route::resource('members', 'memberController'); in the route which, in fact, sets up all the routes associated with BREAD/CRUD in my application. To get the specific details of routes relating to deleting a member or a booking I need to run
php artisan route:list
This I can get the full specifics of the route that were created by the Route::resource() comand. Now I can use this to add permissions to the delete routes for member and booking by adding ->middleware('permission:Delete Booking'); and ->middleware('permission: Delete Member'); to the routes as follows
Route::delete('/bookings/{booking}', 'App\Http\Controllers\BookingController@destroy')->name('bookings.destroy')->middleware('permission:Delete Booking'); Route::delete('/members/{member}','App\Http\Controllers\MemberController@destroy')->name('members.destroy')->middleware('permission:Delete Member');
The downside of this is that it's a bit long-winded and I effectively have to set up the route again even though it was already set up using Route::resource() so there's a level of duplication here. The plus side of this is that it's quite surgical and I can apply specific permissions to specific routes.
Other functions such as Creating a New Member have more than one route associated with the task as there is flow involved in presenting a view to the user and then processing the results of that view.
In this case, we use a closure to assign permissions to that "group" of routes as follows
Route::group(['middleware' => ['permission:Create New Member']], function () { Route::get('/members/create', 'App\Http\Controllers\MemberController@create')->name('members.create'); Route::post('/members/store','App\Http\Controllers\MemberController@store')->name('members.store'); });
This is very handy and can be used to assign permissions to large groups of routes.
Having locked down these four routes in my application I'm now ready to test out my permissions. I've set up the permissions such that only the System Admin has all the permissions and can do anything in the system. The Club Secretary can Delete Bookings and Create New Members but cannot Delete Members.
Now if I login, as a user who is assigned to the Club Secretary Role and attempt to delete a User I receive the following 403 error message
If I login as a System Admin - I am effectively a Super-User who has all checkboxes ticked and has full permissions to do anything in the system. Most systems use the concept of the Super User Adminstrator who has total control. Before I go any further it would make sense to lock down access to the routes relating to Roles and Permissions so that only the System Admin can access them. All the routes for Route::resource('users','usersController'); Should probably also be locked to system admin. Although Spatie points out that it is good practice to always use permissions when locking down access to routes it is also possible to do it at a role level. Add the following lines to your routes\web.php to implement a lockdown of routes relating to implementing security
Route::group(['middleware' => ['role:System Admin']], function () { Route::resource('roles', 'App\Http\Controllers\rolesController'); Route::resource('permissions', 'App\Http\Controllers\permissionsController'); Route::resource('users', 'App\Http\Controllers\usersController'); });
In the next post, I'll discuss how to use a User's role to control what they see on login.