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!
No comments yet. Be the first to comment!
Please log in to post a comment:
Continue with Google