In the evolving landscape of web applications, a one-size-fits-all approach to permissions often falls short. Many developers are acquainted with Role-Based Access Control (RBAC), where users are designated roles, and these roles are accorded certain permissions. However, for intricate applications that demand a heightened layer of precision, a more tailored approach becomes essential.
Enter Granular Project-Based Permissions—a refined system for access control. It’s designed for applications that demand permissions to be discerned not just by user roles but intricately tailored to specific contexts or projects.
In this tutorial, we’ll utilize a project management system as our foundational example to illustrate the potential of this enhanced permission system. By harnessing the Spatie’s permissions package, coupled with Laravel’s robust Eloquent and the dynamic capabilities of Livewire, we will construct an adaptable permission matrix that evaluates both user permissions and their specific project context.
But remember, while our example centers on a project management paradigm, the essence of this guide is adaptability. Whether your next venture is a niche-specific SaaS, an intricate CRM, or a groundbreaking platform yet to be imagined, the techniques illustrated here can be adjusted and scaled to your unique requirements. Dive in, and discover the potential of truly granular permissions in Laravel.
Granular permissions
This solution integrates Spatie’s permissions for a granular, project-specific permission system. The combination of the Spatie package with this custom relationship allows for both general role/permissions and specific project permissions.
Setup Spatie Permissions
Here’s a list for starters, we’ll add more once the new permissions framework is in place.
create project
read project
update project
delete project
create task
read task
update task
delete task
Create project_user_permission table
1. **Enhance Database Structure**:
– Create a table called `project_user_permission` which will have the columns:
– `user_id`
– `project_id`
– `permission_id`
2. **Migrate the New Structure**:
Create a new migration:
php artisan make:migration create_project_user_permission_table
Inside this migration:
public function up() {
Schema::create(‘project_user_permission’, function (Blueprint $table) {
$table->unsignedBigInteger(‘user_id’);
$table->unsignedBigInteger(‘project_id’);
$table->unsignedBigInteger(‘permission_id’);
$table->foreign(‘user_id’)->references(‘id’)->on(‘users’)->onDelete(‘cascade’);
$table->foreign(‘project_id’)->references(‘id’)->on(‘projects’)->onDelete(‘cascade’);
$table->foreign(‘permission_id’)->references(‘id’)->on(‘permissions’)->onDelete(‘cascade’);
$table->unique([‘user_id’, ‘project_id’, ‘permission_id’]);
});
}
Add Method to User Model
public function hasProjectPermission($permissionName, $project) {
$permissionId = Spatie\Permission\Models\Permission::findByName($permissionName)->id;
return DB::table(‘project_user_permission’)
->where(‘user_id’, $this->id)
->where(‘project_id’, $project->id)
->where(‘permission_id’, $permissionId)
->exists();
}
Checking Permissions
To check if a user has the permission ‘edit tasks’ for a specific project:
$user->hasProjectPermission(‘edit tasks’, $specificProject);
In Blade:
@if($user->hasProjectPermission(‘edit tasks’, $specificProject))
<!– Display the edit button for tasks in that specific project –>
@endif
Managing Permissions
To grant a permission for a user on a specific project:
$permissionId = Spatie\Permission\Models\Permission::findByName(‘edit tasks’)->id;
DB::table(‘project_user_permission’)->insert([
‘user_id’ => $user->id,
‘project_id’ => $specificProject->id,
‘permission_id’ => $permissionId
]);
To revoke a permission:
$permissionId = Spatie\Permission\Models\Permission::findByName(‘edit tasks’)->id;
DB::table(‘project_user_permission’)
->where(‘user_id’, $user->id)
->where(‘project_id’, $specificProject->id)
->where(‘permission_id’, $permissionId)
->delete();
Permissions Management Page
Creating a Livewire page to manage permissions for users within a project will involve a few key steps. We’ll create:
1. A Livewire component to display users associated with a project and manage their permissions.
2. The Blade view for the component.
3. Necessary Livewire methods for interaction.
Let’s break it down step-by-step:
Creating a Livewire page to manage permissions for users within a project will involve a few key steps. We’ll create:
1. A Livewire component to display users associated with a project and manage their permissions.
2. The Blade view for the component.
3. Necessary Livewire methods for interaction.
Let’s break it down step-by-step:
namespace App\Http\Livewire;
use Livewire\Component;
use App\Models\Project;
use App\Models\User;
use Spatie\Permission\Models\Permission;
class ManageProjectPermissions extends Component
{
public $project;
public $permissions;
public $users;
public $selectedUser; // For dropdown selection
public function mount(Project $project) {
$this->project = $project;
$this->permissions = Permission::all();
$this->users = $project->users;
$this->selectedUser = null;
}
public function addUserToProject() {
$user = User::find($this->selectedUser);
$this->project->users()->attach($user);
$this->users = $this->project->users; // Refresh users
}
public function removeUserFromProject($userId) {
$this->project->users()->detach($userId);
$this->users = $this->project->users; // Refresh users
}
public function updateUserPermission($userId, $permissionId, $value) {
$user = $this->users->find($userId);
if($value) {
// Grant permission
DB::table(‘project_user_permission’)->updateOrInsert([
‘user_id’ => $user->id,
‘project_id’ => $this->project->id,
‘permission_id’ => $permissionId
]);
} else {
// Revoke permission
DB::table(‘project_user_permission’)
->where(‘user_id’, $user->id)
->where(‘project_id’, $this->project->id)
->where(‘permission_id’, $permissionId)
->delete();
}
}
public function render() {
return view(‘livewire.manage-project-permissions’);
}
}