An open API service indexing awesome lists of open source software.

https://github.com/amdad121/guard-laravel

A powerful, flexible, and developer-friendly role and permission management system for Laravel applications.
https://github.com/amdad121/guard-laravel

acl authorization laravel package permission permissions role role-based-access-control roles

Last synced: 2 months ago
JSON representation

A powerful, flexible, and developer-friendly role and permission management system for Laravel applications.

Awesome Lists containing this project

README

          

# ๐Ÿ›ก๏ธ Guard - Modern Role & Permission Management for Laravel

[![Latest Version on Packagist](https://img.shields.io/packagist/v/amdadulhaq/guard-laravel.svg?style=flat-square)](https://packagist.org/packages/amdadulhaq/guard-laravel)
[![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/amdad121/guard-laravel/run-tests.yml?branch=main&label=tests&style=flat-square)](https://github.com/amdad121/guard-laravel/actions?query=workflow%3Arun-tests+branch%3Amain)
[![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/amdad121/guard-laravel/fix-php-code-style-issues.yml?branch=main&label=code%20style&style=flat-square)](https://github.com/amdad121/guard-laravel/actions?query=workflow%3A"Fix+PHP+code+style+issues"+branch%3Amain)
[![Total Downloads](https://img.shields.io/packagist/dt/amdadulhaq/guard-laravel.svg?style=flat-square)](https://packagist.org/packages/amdadulhaq/guard-laravel)
[![PHP Version](https://img.shields.io/badge/PHP-8.2%2B-777BB4?style=flat-square&logo=php)](https://php.net)
[![Laravel Version](https://img.shields.io/badge/Laravel-10%2F11%2F12%2F13-FF2D20?style=flat-square&logo=laravel)](https://laravel.com)

> A powerful, flexible, and developer-friendly role and permission management system for Laravel applications.

## ๐Ÿš€ Quick Start

Get up and running in 5 minutes:

> **Upgrading from an older version?** Check the [Upgrade Guide](UPGRADE.md) for detailed migration instructions.

### 1. Install via Composer

```bash
composer require amdadulhaq/guard-laravel
```

### 2. Publish and run migrations

```bash
php artisan vendor:publish --tag="guard-migrations"
php artisan migrate
```

### 3. Setup your User model

Choose one setup:

**Roles only**

```php
get('/admin', [AdminController::class, 'index']);
```

## โœจ Features

- ๐ŸŽฏ **Modern PHP & Laravel** - Built for PHP 8.2+ and Laravel 10/11/12/13
- ๐Ÿ” **Flexible Permission System** - Users can have permissions via roles
- ๐ŸŽญ **Wildcard Permissions** - Use `posts.*` to match all post-related permissions
- โšก **Smart Caching** - Automatic cache invalidation for optimal performance
- ๐Ÿ”‘ **Laravel Gate Integration** - Native `@can`, `@canany`, `@cannot` support
- ๐Ÿ›ก๏ธ **Middleware Protection** - `role`, `permission`, and `role_or_permission` middleware
- ๐ŸŽจ **Blade Directives** - `@role`, `@hasrole`, `@hasanyrole`, `@hasallroles`
- ๐Ÿ“ฆ **Type-Safe Enums** - IDE-friendly `PermissionType` and `CacheKey` enums
- ๐Ÿฐ **Guarded Roles** - Protect critical roles from accidental deletion
- ๐Ÿ“ **Permission Groups** - Organize permissions by resource
- ๐ŸŽจ **Interactive Commands** - Laravel Prompts for creating roles/permissions
- ๐Ÿงน **Clean Architecture** - Separated concerns with traits and contracts
- ๐Ÿงช **Developer Tools** - Pint, Pest, Rector, and Larastan included

## ๐Ÿ“‘ Table of Contents

- [Installation](#installation)
- [Upgrade Guide](UPGRADE.md)
- [Configuration](#configuration)
- [Usage](#usage)
- [User Setup](#user-setup)
- [Creating Roles](#creating-roles)
- [Creating Permissions](#creating-permissions)
- [Wildcard Permissions](#wildcard-permissions)
- [Role Management](#role-management)
- [Permission Management](#permission-management)
- [Checking Access](#checking-access)
- [Middleware](#middleware)
- [Gate Integration](#gate-integration)
- [Blade Directives](#blade-directives)
- [Artisan Commands](#artisan-commands)
- [Query Scopes](#query-scopes)
- [Models Reference](#models-reference)
- [Exceptions](#exceptions)
- [Caching](#caching)
- [Database Structure](#database-structure)
- [Enums](#enums)
- [Development](#development)
- [Troubleshooting](#troubleshooting)
- [FAQ](#faq)

## ๐Ÿ“ฆ Installation

### Requirements

- **PHP**: 8.2, 8.3, 8.4, or 8.5
- **Laravel**: 10.x, 11.x, 12.x, or 13.x
- **Database**: MySQL 5.7+, PostgreSQL 9.6+, SQLite 3.8+, or SQL Server 2017+

### Step 1: Install via Composer

```bash
composer require amdadulhaq/guard-laravel
```

### Step 2: Publish Migrations

```bash
php artisan vendor:publish --tag="guard-migrations"
php artisan migrate
```

This creates 4 tables:

- `roles` - Role definitions
- `permissions` - Permission definitions
- `permission_role` - Role-permission relationships
- `role_user` - User-role relationships
Pivot table names are derived from model table names; the defaults shown above are used unless you customize model tables.

### Step 3: Configure User Model

You can use the package in two ways.

**Roles only**

```php
[
'user' => \App\Models\User::class,
'role' => \AmdadulHaq\Guard\Models\Role::class,
'permission' => \AmdadulHaq\Guard\Models\Permission::class,
],
'tables' => [
'roles' => 'roles',
'permissions' => 'permissions',
],
'cache' => [
'enabled' => env('GUARD_CACHE_ENABLED', true),
'roles_duration' => (int) env('GUARD_ROLES_CACHE_DURATION', 3600),
'permissions_duration' => (int) env('GUARD_PERMISSIONS_CACHE_DURATION', 3600),
],
'middleware' => [
'role' => 'role',
'permission' => 'permission',
'role_or_permission' => 'role_or_permission',
],
'wildcard' => [
'enabled' => env('GUARD_WILDCARD_ENABLED', true),
],
];
```

## ๐ŸŽฏ Usage

### User Setup

Use one of these setups depending on what your app needs.

**Roles only**

```php
use AmdadulHaq\Guard\Contracts\Roles as RolesContract;
use AmdadulHaq\Guard\Concerns\HasRoles;

class User extends Authenticatable implements RolesContract
{
use HasRoles;
}
```

**Roles + Permissions**

```php
use AmdadulHaq\Guard\Contracts\User as UserContract;
use AmdadulHaq\Guard\Concerns\HasRoles;
use AmdadulHaq\Guard\Concerns\HasPermissions;

class User extends Authenticatable implements UserContract
{
use HasRoles;
use HasPermissions;
}
```

Notes:

- `HasPermissions` on the user model is for permission checks.
- Users do not receive permissions directly.
- Assign permissions to roles, then users inherit them from those roles.

### Creating Roles

```php
use AmdadulHaq\Guard\Models\Role;

// Create a role
$adminRole = Role::create([
'name' => 'administrator',
'label' => 'Administrator',
'description' => 'Full system access',
'is_guarded' => true, // Protected from deletion
]);

// Create via command
// php artisan guard:create-role moderator "Moderator"
// php artisan guard:create-role moderator "Moderator" 1
// php artisan guard:create-role moderator "Moderator" user@example.com
// php artisan guard:create-role moderator "Moderator" "Jane Doe"
```

**Role Model Methods:**

```php
$role->getName(); // Get role name
$role->isProtectedRole(); // Check if guarded
$role->getPermissionNames(); // Get all permission names
$role->users; // Get users with this role

// Query scopes
Role::guarded()->get(); // Only guarded roles
Role::unguarded()->get(); // Only unguarded roles
```

### Creating Permissions

```php
use AmdadulHaq\Guard\Models\Permission;

// Simple permission
Permission::create([
'name' => 'users.create',
'label' => 'Create Users',
'description' => 'Can create new users',
'group' => 'users', // For organization
]);

// Wildcard permission (auto-sets is_wildcard = true)
Permission::create([
'name' => 'posts.*',
'label' => 'Manage All Posts',
'group' => 'posts',
]);

// Create via command
// php artisan guard:create-permission users.delete "Delete Users"
// php artisan guard:create-permission users.delete "Delete Users" 1
// php artisan guard:create-permission users.delete "Delete Users" admin
```

**Permission Model Methods:**

```php
$permission->getName(); // Get permission name
$permission->getLabel(); // Get human-readable label
$permission->getDescription(); // Get description
$permission->isWildcard(); // Check if wildcard (e.g., posts.*)
$permission->getGroup(); // Get group (e.g., 'users' from 'users.create')
$permission->getType(); // Get PermissionType enum (e.g., PermissionType::CREATE)
$permission->roles; // Get roles with this permission

// Query scopes
Permission::wildcard()->get(); // Only wildcard permissions
Permission::byGroup('users')->get(); // Permissions in users group
```

### Wildcard Permissions

Wildcard permissions automatically match all sub-permissions:

```php
// Create wildcard permission
Permission::create(['name' => 'posts.*']);

// Assign to role
$role->givePermissionTo('posts.*');

// Now user can do all of these:
$user->hasPermission('posts.create'); // true
$user->hasPermission('posts.update'); // true
$user->hasPermission('posts.delete'); // true
$user->hasPermission('posts.publish'); // true
```

The `is_wildcard` boolean is automatically set when the name ends with `*`.

### Role Management

**Assigning Roles:**

```php
// Single role
$user->assignRole('administrator'); // by role name
$user->assignRole($roleModel); // by role model

// Multiple roles in one call
$user->assignRole('administrator', 'editor');
$user->assignRole([$roleModel, $roleId, 'moderator']);

// Sync (replaces all)
$user->syncRoles(['administrator', 'editor']);
$user->syncRoles([$role1->id, $role2->id]);

// Sync without detaching existing
$user->syncRolesWithoutDetaching(['moderator']);

// Revoke
$user->revokeRole('editor');
$user->revokeRole($roleModel);
$user->revokeRoles(); // Revoke all
```

**Checking Roles:**

```php
// Single role
$user->hasRole('administrator'); // true/false

// Multiple roles
$user->hasAllRoles(['admin', 'editor']); // Must have ALL
$user->hasAnyRole(['admin', 'moderator']); // Must have ANY

// Get role names
$user->getRoleNames(); // ['administrator', 'editor']
```

### Permission Management

**Assigning to Roles:**

```php
// Single permission
$role->givePermissionTo('users.create'); // by permission name
$role->givePermissionTo($permissionModel); // by permission model

// Multiple permissions in one call
$role->givePermissionTo('users.create', 'users.edit');
$role->givePermissionTo([$permissionModel, $permissionId, 'users.delete']);

// Sync (replaces all)
$role->syncPermissions(['users.create', 'users.edit']);
$role->syncPermissions([$perm1->id, $perm2->id]);

// Revoke
$role->revokePermissionTo('users.delete');
$role->revokePermissionTo($permissionModel);
$role->revokeAllPermissions();
```

**Checking Role Permissions:**

```php
$role->hasPermissionTo('users.edit'); // Check if role has permission
$role->getPermissionNames(); // Get all permission names
```

**Checking User Permissions:**

```php
// Check by name
$user->hasPermission('users.create');

// Check by model
$user->hasPermission($permissionModel);

// Wildcard matching
$user->hasPermission('posts.*');

// Get all permissions inherited from roles
$user->getPermissions();

// Get permission names array
$user->getPermissionNames(); // ['users.create', 'users.edit']
```

### Checking Access

**Role Checking:**

```php
if ($user->hasRole('administrator')) {
// User has administrator role
}

if ($user->hasAllRoles(['admin', 'editor'])) {
// User has both roles
}

if ($user->hasAnyRole(['admin', 'moderator'])) {
// User has at least one role
}

// Get all role names
$user->getRoleNames(); // ['administrator', 'editor']
```

**Permission Checking:**

```php
if ($user->hasPermission('users.create')) {
// User can create users
}

if ($user->hasPermission('posts.*')) {
// User has wildcard permission for posts
}
```

### Middleware

All middleware supports multiple values (requires ANY):

```php
// Role middleware
Route::middleware('role:administrator')->get('/admin', [AdminController::class, 'index']);

// Multiple roles (requires ANY)
Route::middleware('role:admin,editor')->group(function () {
Route::get('/dashboard', [DashboardController::class, 'index']);
});

// Permission middleware
Route::middleware('permission:users.create')->post('/users', [UserController::class, 'store']);

// Multiple permissions (requires ANY)
Route::middleware('permission:users.create,users.edit')->put('/users/{id}', [UserController::class, 'update']);

// Role OR permission middleware
Route::middleware('role_or_permission:admin,users.create')->get('/users', [UserController::class, 'index']);

// Multiple role_or_permission
Route::middleware('role_or_permission:admin,editor,posts.manage')->group(function () {
Route::post('/manage', [Controller::class, 'handle']);
});
```

### Gate Integration

The package automatically registers Gates for all permissions and roles:

```php
// In controllers
public function store(Request $request)
{
$this->authorize('users.create');
// User can create users
}

// Using Gate facade
use Illuminate\Support\Facades\Gate;

if (Gate::allows('users.create')) {
// Allowed
}

if (Gate::denies('users.delete')) {
abort(403, 'Permission denied');
}

// Check for specific user
if (Gate::forUser($otherUser)->allows('posts.edit')) {
// That user can edit posts
}

// Authorize roles
$this->authorize('administrator');
```

### Blade Directives

Guard provides custom Blade directives for role checking, in addition to Laravel's built-in `@can` directives:

**Custom Role Directives:**

```blade
@role('administrator')


Admin Dashboard



@endrole

@hasrole('editor')

Editor content here


@endhasrole

@hasanyrole(['administrator', 'moderator'])

Content for admins or moderators


@endhasanyrole

@hasallroles(['administrator', 'editor'])

Only for users with BOTH admin AND editor roles


@endhasallroles
```

**Built-in Laravel Directives (via Gate integration):**

```blade
@can('users.create')
Create User
@endcan

@canany(['users.create', 'users.edit'])

You can manage users


@endcanany

@cannot('users.delete')

You cannot delete users


@endcannot
```

### Artisan Commands

**Create a Role:**

```bash
php artisan guard:create-role admin Administrator

# With optional user assignment as the third positional argument
php artisan guard:create-role moderator Moderator 1
```

**Create a Permission:**

```bash
php artisan guard:create-permission users.create "Create Users"

# With optional role assignment as the third positional argument
php artisan guard:create-permission posts.delete "Delete Posts" 1
```

Both commands support Laravel Prompts when optional assignment arguments are omitted.

- `guard:create-role` prompts for an optional user identifier and accepts a user ID, email, or name.
- `guard:create-permission` prompts for an optional role identifier and accepts a role ID or role name.

### Query Scopes

```php
// Users with a specific role
User::query()->withRoles('administrator')->get();

// Users with a specific permission inherited through roles
User::query()->withPermissions('users.create')->get();

// Role scopes
Role::query()->guarded()->get();
Role::query()->unguarded()->get();

// Permission scopes
Permission::query()->wildcard()->get();
Permission::query()->byGroup('users')->get();
```

## ๐Ÿ“š Models Reference

### User Model (via Traits)

**HasRoles trait provides:**

- `roles()` - BelongsToMany relationship
- `assignRole(...$roles)` - Assign one or more roles
- `syncRoles(array $roles, bool $detach = true)` - Sync roles
- `syncRolesWithoutDetaching(array $roles)` - Sync without detaching
- `revokeRole($role)` - Revoke specific role
- `revokeRoles()` - Revoke all roles
- `getRoleNames()` - Get all role names
- `hasRole($role)` - Check single role
- `hasAllRoles(...$roles)` - Check all roles
- `hasAnyRole(...$roles)` - Check any role

**HasPermissions trait provides:**

- `getPermissionNames()` - Get permission names inherited from roles
- `hasPermission($permission)` - Check permission (by name or model)
- `getPermissions()` - Get all permissions inherited from roles

### Role Model

**Properties:**

- `name` (string, unique)
- `label` (string, nullable)
- `description` (text, nullable)
- `is_guarded` (boolean)

**Methods:**

- `getName()` - Get role name
- `isProtectedRole()` - Check if guarded
- `getPermissionNames()` - Get assigned permission names
- `permissions()` - BelongsToMany to permissions
- `users()` - BelongsToMany to users

**Scopes:**

- `guarded()` - Only guarded roles
- `unguarded()` - Only unguarded roles

### Permission Model

**Properties:**

- `name` (string, unique)
- `label` (string, nullable)
- `description` (text, nullable)
- `group` (string, nullable, indexed)
- `is_wildcard` (boolean, auto-set)

**Methods:**

- `getName()` - Get permission name
- `getLabel()` - Get human-readable label
- `getDescription()` - Get description
- `isWildcard()` - Check if wildcard pattern
- `getGroup()` - Get resource group (e.g., 'users')
- `getType()` - Get PermissionType enum
- `roles()` - BelongsToMany to roles
- `giveRoleTo(...$roles)` - Give one or more roles to permission
- `syncRoles(array $roles)` - Sync roles
- `revokeRole($role)` - Revoke role
- `assignRole(...$roles)` - Alias for giveRoleTo

**Scopes:**

- `wildcard()` - Only wildcard permissions
- `byGroup($group)` - Filter by group

## ๐Ÿšจ Exceptions

```php
use AmdadulHaq\Guard\Exceptions\PermissionDeniedException;
use AmdadulHaq\Guard\Exceptions\RoleDoesNotExistException;
use AmdadulHaq\Guard\Exceptions\PermissionDoesNotExistException;

// Permission denied
throw PermissionDeniedException::create('users.delete');
throw PermissionDeniedException::roleNotAssigned('administrator');

// Role not found
throw RoleDoesNotExistException::named('admin');
throw RoleDoesNotExistException::withId(123);

// Permission not found
throw PermissionDoesNotExistException::named('users.delete');
throw PermissionDoesNotExistException::withId(456);
```

## ๐Ÿ’พ Caching

The package uses intelligent caching:

```php
use AmdadulHaq\Guard\Facades\Guard;

// Clear cache manually
Guard::clearCache();
```

**Cache is automatically cleared when:**

- Roles or permissions are created/updated/deleted
- Role-permission relationships change

**Configuration:**

```php
'cache' => [
'enabled' => true,
'roles_duration' => 3600, // 1 hour
'permissions_duration' => 3600, // 1 hour
],
```

## ๐Ÿ—„๏ธ Database Structure

### Roles Table

```php
Schema::create('roles', function (Blueprint $table) {
$table->id();
$table->string('name')->unique();
$table->string('label')->nullable();
$table->text('description')->nullable();
$table->boolean('is_guarded')->default(false);
$table->timestamps();
});
```

### Permissions Table

```php
Schema::create('permissions', function (Blueprint $table) {
$table->id();
$table->string('name')->unique();
$table->string('label')->nullable();
$table->text('description')->nullable();
$table->string('group')->nullable()->index();
$table->boolean('is_wildcard')->default(false);
$table->timestamps();
});
```

### Permission-Role Pivot

```php
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']);
});
```

### Role-User Pivot

```php
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']);
});
```

## ๐Ÿ”ข Enums

### PermissionType

```php
use AmdadulHaq\Guard\Enums\PermissionType;

PermissionType::CREATE->label(); // "Create"
PermissionType::READ->label(); // "Read"
PermissionType::WRITE->label(); // "Write"
PermissionType::UPDATE->label(); // "Update"
PermissionType::DELETE->label(); // "Delete"
PermissionType::VIEW_ANY->label(); // "View any"
PermissionType::VIEW->label(); // "View"
PermissionType::RESTORE->label(); // "Restore"
PermissionType::FORCE_DELETE->label(); // "Force delete"
PermissionType::MANAGE->label(); // "Manage"
```

### CacheKey

```php
use AmdadulHaq\Guard\Enums\CacheKey;

CacheKey::PERMISSIONS->value; // 'guard_permissions'
CacheKey::ROLES->value; // 'guard_roles'
```

## ๐Ÿ› ๏ธ Development

### Code Quality Tools

```bash
# Rector (code refactoring)
composer refactor
composer refactor:check

# Laravel Pint (code style)
composer lint
composer lint:check

# Pest (testing)
composer test
composer test-coverage

# Larastan (static analysis)
composer analyse
```

### Running Tests

```bash
# Run all tests
composer test

# With coverage
composer test-coverage
```

## ๐Ÿ”ง Troubleshooting

### Common Issues

**Issue: `Class 'AmdadulHaq\Guard\Concerns\HasRoles' not found`**

Solution:

```bash
composer dump-autoload
```

**Issue: `Target class [role] does not exist.`**

Solution:

```bash
php artisan config:clear
```

**Issue: Permissions not being recognized**

Solution:

```bash
php artisan cache:clear
# Or
php artisan tinker --execute="\AmdadulHaq\Guard\Facades\Guard::clearCache()"
```

### Performance Tips

1. **Keep caching enabled** in production
2. **Use wildcard permissions** to reduce permission count
3. **Filter at database level** instead of loading all users:

```php
// โœ… Good
User::whereHas('roles', fn ($q) => $q->where('name', 'admin'))->get();

// โŒ Less efficient
User::all()->filter(fn ($u) => $u->hasRole('admin'));
```

4. **Eager load** when needed:
```php
User::with(['roles', 'roles.permissions'])->get();
```

## โ“ FAQ

**Q: Can I use this with Laravel Sanctum?**

A: Yes! Guard works seamlessly with Sanctum and any auth system.

**Q: Can users have permissions without roles?**

A: No, users receive permissions via roles.

**Q: How do wildcard permissions work?**

A: Create a permission like `posts.*` and it automatically matches `posts.create`, `posts.edit`, etc.

**Q: Can I customize table names?**

A: Yes, publish the config and modify the `tables` section.

**Q: Does it work with multiple guards?**

A: Yes, it integrates with Laravel's authorization system.

**Q: Is there a UI for managing roles?**

A: Guard is backend-only. For a UI, consider Filament Shield or build your own.

**Q: What Blade directives does Guard provide?**

A: Guard ships with `@role`, `@hasrole`, `@hasanyrole`, and `@hasallroles`. Laravel's built-in `@can`, `@canany`, and `@cannot` also work through Gate integration.

**Q: Can permissions be assigned to permissions?**

A: No, permissions are assigned to roles.

## ๐Ÿค Contributing

We welcome contributions! Please see [CONTRIBUTING](CONTRIBUTING.md) for details.

## ๐Ÿ“ Changelog

See [CHANGELOG](CHANGELOG.md) for recent changes.

## ๐Ÿ”’ Security

Please review [our security policy](../../security/policy) for reporting vulnerabilities.

## ๐Ÿ‘ Credits

![Contributors](https://contrib.rocks/image?repo=amdad121/guard-laravel)

## ๐Ÿ“„ License

The MIT License (MIT). See [License File](LICENSE.md) for details.

---

Made with โค๏ธ for the Laravel community