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) permission_role (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_permission_role_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();
});
permission_role Pivot TableSchema::create('permission_role', 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!
Сергей Галбур
Oct 12, 2025 08:03 AM
Kritim Yantra
Oct 12, 2025 02:08 PM
Please log in to post a comment:
Sign in with Google
Kritim Yantra
Kritim Yantra
Kritim Yantra
Сергей Галбур
Oct 16, 2025 02:08 PM
Kritim Yantra
Oct 20, 2025 02:26 PM