Kritim Yantra
Mar 27, 2025
Managing user roles and permissions is essential for controlling access in web applications. While packages like Spatie Laravel-Permission exist, you can easily implement this in pure Laravel without external dependencies.
In this guide, we’ll cover:
✅ Database Setup for Roles & Permissions
✅ Assigning Roles to Users
✅ Checking Permissions in Controllers & Views
✅ Middleware for Role-Based Access
Let’s build a role-based system from scratch!
🔹 Full control over the logic
🔹 No dependency on third-party packages
🔹 Lightweight & customizable
🔹 Great for learning Laravel’s core features
We’ll use 4 tables:
users
(Default Laravel users table) roles
(Admin, Editor, User) permissions
(create-post, edit-post, delete-post) role_permission
(Pivot table linking roles and permissions)Run these commands:
php artisan make:migration create_roles_table
php artisan make:migration create_permissions_table
php artisan make:migration create_role_permission_table
roles
Table MigrationSchema::create('roles', function (Blueprint $table) {
$table->id();
$table->string('name'); // admin, editor, user
$table->timestamps();
});
permissions
Table MigrationSchema::create('permissions', function (Blueprint $table) {
$table->id();
$table->string('name'); // create-post, edit-post, delete-post
$table->timestamps();
});
role_permission
Pivot TableSchema::create('role_permission', function (Blueprint $table) {
$table->foreignId('role_id')->constrained();
$table->foreignId('permission_id')->constrained();
$table->primary(['role_id', 'permission_id']);
});
role_id
to users
Tablephp artisan make:migration add_role_id_to_users_table
Schema::table('users', function (Blueprint $table) {
$table->foreignId('role_id')->default(3)->constrained(); // Default role: 'user'
});
Run migrations:
php artisan migrate
User
Model// app/Models/User.php
public function role()
{
return $this->belongsTo(Role::class);
}
public function hasPermission($permissionName)
{
return $this->role->permissions()->where('name', $permissionName)->exists();
}
Role
Model// app/Models/Role.php
public function permissions()
{
return $this->belongsToMany(Permission::class);
}
Permission
Model// app/Models/Permission.php
public function roles()
{
return $this->belongsToMany(Role::class);
}
Let’s populate the database with sample data.
php artisan make:seeder RolePermissionSeeder
// database/seeders/RolePermissionSeeder.php
public function run()
{
// Create Roles
$admin = Role::create(['name' => 'admin']);
$editor = Role::create(['name' => 'editor']);
$user = Role::create(['name' => 'user']);
// Create Permissions
$createPost = Permission::create(['name' => 'create-post']);
$editPost = Permission::create(['name' => 'edit-post']);
$deletePost = Permission::create(['name' => 'delete-post']);
// Assign Permissions to Roles
$admin->permissions()->attach([$createPost->id, $editPost->id, $deletePost->id]);
$editor->permissions()->attach([$createPost->id, $editPost->id]);
$user->permissions()->attach([$createPost->id]);
}
Run the seeder:
php artisan db:seed --class=RolePermissionSeeder
// app/Http/Controllers/PostController.php
public function create()
{
if (!auth()->user()->hasPermission('create-post')) {
abort(403, 'Unauthorized action.');
}
return view('posts.create');
}
php artisan make:middleware CheckRole
// app/Http/Middleware/CheckRole.php
public function handle($request, Closure $next, $role)
{
if (auth()->check() && auth()->user()->role->name === $role) {
return $next($request);
}
abort(403, 'Access Denied');
}
Add this tobootstrap/app.php
:
->withMiddleware(function (Middleware $middleware) {
$middleware->alias([
'role' => \App\Http\Middleware\CheckRole::class,
]);
})
Route::get('/admin/dashboard', function () {
return view('admin.dashboard');
})->middleware('role:admin');
@if(auth()->user()->hasPermission('edit-post'))
<a href="/posts/{{ $post->id }}/edit">Edit Post</a>
@endif
// Make a user an admin
$user = User::find(1);
$user->role_id = 1; // admin role
$user->save();
✔ Use caching for permissions to reduce database queries.
✔ Avoid hardcoding role/permission names (use constants).
✔ Test permissions thoroughly with unit tests.
You’ve just built a full role-permission system in Laravel without any packages!
🔹 Database Setup → Roles, Permissions, Pivot Tables
🔹 Models & Relationships → User
, Role
, Permission
🔹 Middleware & Controllers → Restrict access
🔹 Blade Checks → Show/hide UI elements
🚀 Now go ahead and implement this in your Laravel app!
Transform from beginner to Laravel expert with our personalized Coaching Class starting June 16, 2025. Limited enrollment ensures focused attention.
1-hour personalized coaching
Build portfolio applications
Industry-standard techniques
Interview prep & job guidance
Complete your application to secure your spot
Thank you for your interest in our Laravel mentorship program. We'll contact you within 24 hours with next steps.
No comments yet. Be the first to comment!
Please log in to post a comment:
Sign in with Google