Skip to content

Role-Based Access Control (RBAC) for Filament Admin

This document explains how to implement and use role-based access control in the EasyOTC Filament admin panel.

Where this lives

  • Role enum: app/Enums/RoleEnum.php (canonical source for role values)
  • Setup commands: php artisan roles:setup and php artisan roles:permissions
  • Trait: app/Traits/HasRoleAccess.php
  • Middleware: App\Http\Middleware\RoleBasedAccess (alias role.access)

Where to access the admin panel

EnvironmentURLCredentials
Localhttp://localhost:8000/adminSeeded otc_one_admin user (see seeders)
Staginghttps://stage-api.easyotc.com/adminSee /access

Only users with the otc_one_admin, carrier_admin, or agent role can log in to /admin. member users authenticate against the storefront.

Overview

The system supports four roles (defined in app/Enums/RoleEnum.php):

  • OTC One Admin (otc_one_admin): Full access to all resources and actions
  • Carrier Admin (carrier_admin): Carrier-scoped admin; read-only access to products and orders for their carrier
  • Agent (agent): Most limited admin access, read-only for most resources
  • Member (member): Storefront customer; no admin panel access

Setup

1. Run the Setup Commands

bash
# Setup roles
php artisan roles:setup

# Setup permissions
php artisan roles:permissions

2. Assign Roles to Users

Users can be assigned roles through the admin panel or programmatically:

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

The navigation is automatically filtered based on user roles:

  • Super Admin: Sees all navigation items
  • Carrier Admin: Sees only Products and Orders
  • Agent: Sees only Products and Orders

Resource Access Control

Using the BaseResource Class

Extend BaseResource for automatic role checking:

php
use App\Filament\Resources\BaseResource;

class ProductResource extends BaseResource
{
    // Override methods for custom access logic
    public static function canAccess(): bool
    {
        $user = auth()->user();
        
        if (!$user) {
            return false;
        }

        // Super admin can access everything
        if ($user->hasRole(RoleEnum::OTC_ONE_ADMIN->value)) {
            return true;
        }

        // Carrier admin and agents can access products
        return $user->hasAnyRole([
            RoleEnum::CARRIER_ADMIN->value,
            RoleEnum::AGENT->value
        ]);
    }
}

Manual Implementation

For existing resources, add these methods:

php
use App\Traits\HasRoleAccess;
use App\Enums\RoleEnum;

class OrderResource extends Resource
{
    use HasRoleAccess;

    public static function canAccess(): bool
    {
        // Your custom logic here
    }

    public static function canCreate(): bool
    {
        // Your custom logic here
    }

    public static function canEdit(Model $record): bool
    {
        // Your custom logic here
    }

    public static function canDelete(Model $record): bool
    {
        // Your custom logic here
    }

    public static function canView(Model $record): bool
    {
        // Your custom logic here
    }
}

Permission Matrix

ResourceActionSuper AdminCarrier AdminAgent
ProductsView✅ (All)✅ (Own Carrier Only)
ProductsCreate❌ (Read-only)
ProductsEdit❌ (Read-only)
ProductsDelete
OrdersView✅ (All)✅ (Own Carrier Only)
OrdersCreate❌ (Read-only)
OrdersEdit❌ (Read-only)
OrdersDelete
MembersView
MembersCreate
MembersEdit
MembersDelete
CarriersView
CarriersCreate
CarriersEdit
CarriersDelete

Carrier-Specific Filtering

Carrier Admin users have additional restrictions:

  • Can only view Products and Orders that belong to their specific carrier_id
  • Read-only access - cannot create, edit, or delete records
  • Navigation shows only Products and Orders sections

Helper Methods

The HasRoleAccess trait provides several helper methods:

php
// Check if user has a specific role
$this->hasRole('carrier_admin');
$this->hasRole(RoleEnum::CARRIER_ADMIN);

// Check if user has any of the specified roles
$this->hasAnyRole(['carrier_admin', 'agent']);

// Check if user is a super admin
$this->isSuperAdmin();

// Check if user is a carrier admin
$this->isCarrierAdmin();

// Check if user is an agent
$this->isAgent();

// Check if user can access a specific resource
$this->canAccessResource('products');

// Check if user can perform a specific action on a resource
$this->canPerformAction('products', 'edit');

Middleware

The RoleBasedAccess middleware is automatically applied to the admin panel. You can also use it on specific routes:

php
Route::middleware(['role.access:carrier_admin'])->group(function () {
    // Routes only accessible by carrier admins
});

Customizing Access Control

Adding New Roles

  1. Add the role to RoleEnum
  2. Update the SetupRolesCommand
  3. Update the RoleBasedNavigation class
  4. Update the HasRoleAccess trait

Modifying Permissions

  1. Update the SetupRolePermissionsCommand
  2. Modify the permission matrix in the relevant resource classes
  3. Update the navigation items in RoleBasedNavigation

Testing

To test role-based access:

  1. Create test users with different roles
  2. Log in as each user
  3. Verify that navigation items and actions are properly restricted
  4. Test that unauthorized access returns 403 errors

Troubleshooting

Common Issues

  1. Navigation not updating: Clear the application cache
  2. Permissions not working: Run php artisan roles:permissions again
  3. Users can't access admin: Ensure they have the correct role assigned

Debugging

Use the helper methods to debug access issues:

php
// Check user's roles
dd(auth()->user()->getRoleNames());

// Check if user can access a resource
dd($this->canAccessResource('products'));

// Check if user can perform an action
dd($this->canPerformAction('products', 'edit'));