Access Control Lists (ACL) are a fundamental part of web application security, allowing you to control access to various resources based on user roles. In Laravel, implementing Role-Based Access Control (RBAC) with ACL is a powerful way to manage user permissions. In this post, we'll explore how to implement ACL in Laravel with a role-based approach, providing a full example with sample output.
Step 1: Set Up the Database
First, create a database table to store roles and permissions. For this example, we'll create two tables: roles
and permissions
.
CREATE TABLE roles (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
description VARCHAR(255) NOT NULL
);
CREATE TABLE permissions (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
description VARCHAR(255) NOT NULL
);
Step 2: Create Models and Relationships
Next, create Eloquent models for the Role
and Permission
tables, along with their relationships.
php artisan make:model Role
php artisan make:model Permission
In the models, define the many-to-many relationship between roles and permissions:
// Role.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Role extends Model
{
protected $fillable = ['name', 'description'];
public function permissions()
{
return $this->belongsToMany(Permission::class);
}
}
// Permission.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Permission extends Model
{
protected $fillable = ['name', 'description'];
public function roles()
{
return $this->belongsToMany(Role::class);
}
}
Step 3: Create Middleware
Now, create a middleware that checks whether the authenticated user has the required role to access specific routes.
php artisan make:middleware RoleMiddleware
In the RoleMiddleware.php
file, implement the logic to check the user's role:
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class RoleMiddleware
{
public function handle($request, Closure $next, ...$roles)
{
if (!Auth::check()) {
return redirect()->route('login');
}
$user = Auth::user();
foreach ($roles as $role) {
if ($user->hasRole($role)) {
return $next($request);
}
}
return redirect()->route('unauthorized');
}
}
Step 4: Register the Middleware
Register the RoleMiddleware
in the app/Http/Kernel.php
file by adding it to the $routeMiddleware
array.
protected $routeMiddleware = [
// Other middleware
'role' => \App\Http\Middleware\RoleMiddleware::class,
];
Step 5: Define Routes and Controller
In this example, let's create two routes: one that requires the admin
role and another that requires the editor
role. We'll use a controller to handle the requests.
// routes/web.php
use App\Http\Controllers\HomeController;
Route::get('/', [HomeController::class, 'index']);
Route::get('/admin', [HomeController::class, 'admin'])->middleware('role:admin');
Route::get('/editor', [HomeController::class, 'editor'])->middleware('role:editor');
Route::get('/unauthorized', [HomeController::class, 'unauthorized'])->name('unauthorized');
Step 6: Implement the Controller Logic
Create a controller to handle the routes defined in Step 5 and check the user's role.
php artisan make:controller HomeController
In the HomeController.php
file:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class HomeController extends Controller
{
public function index()
{
return view('welcome');
}
public function admin()
{
return view('admin');
}
public function editor()
{
return view('editor');
}
public function unauthorized()
{
return view('unauthorized');
}
}
Step 7: Implement Role Check in the User Model
In the User
model, define a method to check if the user has a specific role.
// User.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
// Your existing User model code
public function hasRole($role)
{
return $this->roles()->where('name', $role)->exists();
}
}
Step 8: Sample Views
Create views for the admin
, editor
, and unauthorized
routes.
<!-- resources/views/admin.blade.php -->
@extends('layouts.app')
@section('content')
<h1>Welcome, Admin!</h1>
<p>This is the Admin Dashboard.</p>
@endsection
<!-- resources/views/editor.blade.php -->
@extends('layouts.app')
@section('content')
<h1>Welcome, Editor!</h1>
<p>This is the Editor Dashboard.</p>
@endsection
<!-- resources/views/unauthorized.blade.php -->
@extends('layouts.app')
@section('content')
<h1>Unauthorized Access</h1>
<p>You do not have permission to access this page.</p>
@endsection
Step 9: Test the Implementation
Now, run your Laravel application and access the routes /
, /admin
, and /editor
. You should be redirected to the /login
route, as we have not implemented authentication in this example.