Laravel 12 Table Relationships: A Complete Guide to Roles and Permissions (RBAC)

Author

Kritim Yantra

May 25, 2025

Laravel 12 Table Relationships: A Complete Guide to Roles and Permissions (RBAC)

Building modern web applications often requires controlling user access to specific features. Whether it's an admin-only dashboard or content restricted by roles, Role-Based Access Control (RBAC) is the go-to solution. In this comprehensive guide, we’ll walk you through setting up Roles and Permissions in Laravel 12, covering:

✅ Database design
✅ Model relationships
✅ Middleware for access control
✅ Blade directives for views
✅ Seeding roles and permissions

Let's get started!


🚀 What is RBAC?

Role-Based Access Control (RBAC) is a system where you assign permissions to roles, and then roles to users. For example:

  • The Admin role might have permissions to manage users, edit content, and publish articles.
  • A User role may only view content.

This setup ensures a clean, maintainable system for controlling access across your Laravel application.


🏗️ Database Design

We'll need the following tables:

📂 1. users table (default in Laravel)

Schema::create('users', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->string('email')->unique();
    $table->timestamp('email_verified_at')->nullable();
    $table->string('password');
    $table->rememberToken();
    $table->timestamps();
});

📂 2. roles table

Schema::create('roles', function (Blueprint $table) {
    $table->id();
    $table->string('name')->unique();
    $table->string('description')->nullable();
    $table->timestamps();
});

📂 3. permissions table

Schema::create('permissions', function (Blueprint $table) {
    $table->id();
    $table->string('name')->unique();
    $table->string('description')->nullable();
    $table->timestamps();
});

📂 4. Pivot Tables

role_user (many-to-many: users ↔️ roles)

Schema::create('role_user', function (Blueprint $table) {
    $table->foreignId('role_id')->constrained()->cascadeOnDelete();
    $table->foreignId('user_id')->constrained()->cascadeOnDelete();
    $table->primary(['role_id', 'user_id']);
});

permission_role (many-to-many: roles ↔️ permissions)

Schema::create('permission_role', function (Blueprint $table) {
    $table->foreignId('permission_id')->constrained()->cascadeOnDelete();
    $table->foreignId('role_id')->constrained()->cascadeOnDelete();
    $table->primary(['permission_id', 'role_id']);
});

🧩 Defining Model Relationships

👤 User Model

public function roles()
{
    return $this->belongsToMany(Role::class);
}

public function assignRole($role)
{
    if (is_string($role)) {
        $role = Role::whereName($role)->firstOrFail();
    }
    return $this->roles()->syncWithoutDetaching($role);
}

public function hasRole($role)
{
    if (is_string($role)) {
        return $this->roles->contains('name', $role);
    }
    return !! $role->intersect($this->roles)->count();
}

public function permissions()
{
    return $this->roles->map->permissions->flatten()->pluck('name')->unique();
}

public function hasPermission($permission)
{
    return $this->permissions()->contains($permission);
}

🎓 Role Model

public function users()
{
    return $this->belongsToMany(User::class);
}

public function permissions()
{
    return $this->belongsToMany(Permission::class);
}

public function givePermissionTo($permission)
{
    if (is_string($permission)) {
        $permission = Permission::whereName($permission)->firstOrFail();
    }
    return $this->permissions()->syncWithoutDetaching($permission);
}

🔒 Permission Model

public function roles()
{
    return $this->belongsToMany(Role::class);
}

🔑 Assigning Roles and Permissions

✅ Assign a Role to a User

$user = User::find(1);
$user->assignRole('admin');

✅ Give Permission to a Role

$adminRole = Role::where('name', 'admin')->first();
$adminRole->givePermissionTo('edit-users');

✅ Check Roles and Permissions

if ($user->hasRole('admin')) {
    // Admin access granted
}

if ($user->hasPermission('edit-users')) {
    // Permission granted
}

🛡️ Middleware for Route Protection

Role Middleware

Create:

php artisan make:middleware RoleMiddleware

Implement:

public function handle(Request $request, Closure $next, $role)
{
    if (!auth()->user()->hasRole($role)) {
        abort(403, 'Unauthorized action.');
    }
    return $next($request);
}

Register in Kernel.php:

'role' => \App\Http\Middleware\RoleMiddleware::class,

Usage:

Route::get('/admin', fn() => 'Admin Panel')->middleware(['auth', 'role:admin']);

Permission Middleware

Similar steps apply:

php artisan make:middleware PermissionMiddleware

Implement:

public function handle(Request $request, Closure $next, $permission)
{
    if (!auth()->user()->hasPermission($permission)) {
        abort(403, 'Unauthorized action.');
    }
    return $next($request);
}

🖌️ Blade Directives

Add to AppServiceProvider:

Blade::if('role', fn($role) => auth()->check() && auth()->user()->hasRole($role));
Blade::if('permission', fn($permission) => auth()->check() && auth()->user()->hasPermission($permission));

Usage:

@role('admin')
    <p>Welcome, Admin!</p>
@endrole

@permission('edit-users')
    <button>Edit User</button>
@endpermission

🌱 Seeding Initial Roles & Permissions

Create a seeder:

php artisan make:seeder RolesAndPermissionsSeeder

Example:

public function run()
{
    $admin = Role::create(['name' => 'admin']);
    $editor = Role::create(['name' => 'editor']);

    $permissions = ['manage-users', 'edit-content', 'publish-content'];
    foreach ($permissions as $perm) {
        Permission::create(['name' => $perm]);
    }

    $admin->givePermissionTo(Permission::all());
    $editor->givePermissionTo(['edit-content', 'publish-content']);
}

Run:

php artisan db:seed --class=RolesAndPermissionsSeeder

✨ Best Practices

✅ Use Enums for role/permission names.
Cache permissions for performance.
✅ Build an admin UI for roles & permissions.
✅ Add audit logs for changes.
✅ Write tests for authorization logic.


🏁 Conclusion

By following this guide, you now have a powerful, flexible, and scalable Roles & Permissions system in Laravel 12! 🚀

✅ Database relationships? ✔️
✅ Model methods? ✔️
✅ Middleware & Blade directives? ✔️
✅ Seeding data? ✔️

Keep building and securing your Laravel apps with confidence! 💪

LIVE MENTORSHIP ONLY 5 SPOTS

Laravel Mastery
Coaching Class Program

KritiMyantra

Transform from beginner to Laravel expert with our personalized Coaching Class starting June 20, 2025. Limited enrollment ensures focused attention.

Daily Sessions

1-hour personalized coaching

Real Projects

Build portfolio applications

Best Practices

Industry-standard techniques

Career Support

Interview prep & job guidance

Total Investment
$200
Duration
30 hours
1h/day

Enrollment Closes In

Days
Hours
Minutes
Seconds
Spots Available 5 of 10 remaining
Next cohort starts:
June 20, 2025

Join the Program

Complete your application to secure your spot

Application Submitted!

Thank you for your interest in our Laravel mentorship program. We'll contact you within 24 hours with next steps.

What happens next?

  • Confirmation email with program details
  • WhatsApp message from our team
  • Onboarding call to discuss your goals

Tags

Comments

No comments yet. Be the first to comment!

Please log in to post a comment:

Sign in with Google

Related Posts