Spatie Role 과 Permission 으로 Laravel app ACL 관리하기
서비스를 만들다 보면 사용자의 role 에 따라 접근 가능한 resource 나 action 을 제어해야 하는 경우가 자주 발생합니다.
laravel-permission 은 라라벨 패키지의 명가 Spatie 에서 만든 ACL(Access Control List) 라이브러리로 Eloquent 모델에 쉽게 ACL 을 연동할 수 있게 해 줍니다.
설치
composer require spatie/laravel-permission
Laravel 에서는 Provider auto discovery 기능이 있지만 개인적으로는 전체 목록을 확인하기 용이해서 수동 등록을 선호합니다. config/app.php 에 Provider 를 등록합니다.
'providers' => [ // ... Spatie\Permission\PermissionServiceProvider::class, ];
설정 파일인 config/permission.php 를 퍼블리싱 해줍니다.
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"
config 캐시 기능을 사용한다면 캐시를 정리해 줍니다.
php artisan optimize:clear # or php artisan config:clear
이제 role 과 permission 테이블을 migration 합니다.
php artisan migrate
Role 생성/관리
Role 과 Permission 을 적용할 Eloquent Model 클래스에 Spatie\Permission\Traits\HasRoles 트레이트를 추가해 주면 됩니다.
use Spatie\Permission\Traits\HasRoles; class User extends Authenticatable { use HasFactory, Notifiable; use HasRoles;
Role 과 Permission 이라는 Eloquent Model 이 제공되므로 이걸로 role 과 permission 을 만들 수 있습니다.
use Spatie\Permission\Models\Role; use Spatie\Permission\Models\Permission; $role = Role::create(['name' => 'editors']); $admin_role = Role::create(['name' => 'sys-admin']); $perm_create = Permission::create(['name' => 'create articles']); $perm_edit = Permission::create(['name' => 'edit articles']);
role 은 permission 의 그룹이므로 개별 permission 은 2가지 방법으로 role 과 연결할 수 있습니다.
먼저 Role 클래스의 givePermissionTo(Permission $permission) 을 사용할 수 있습니다.
$role->givePermissionTo($perm_create ); $role->givePermissionTo($perm_edit );
또는 Permission 클래스의 assignRole(Role $role) 을 사용해도 됩니다.
$perm_create ->assignRole($role); $perm_edit ->assignRole($role);
여러 개의 permissions 을 Role 과 동기화하려면 다음 방법을 사용합니다.
$role->syncPermissions([$perm_create, $perm_edit ]); $permission->syncRoles($roles);
하나의 permission 을 여러 개의 role 에 연결하려면 syncRoles() 를 사용하면 됩니다.
$permission->syncRoles($roles);
role 에서 permission 을 제거하려면 revokedPermmionTo(Permission $permission) 나 removeRole (Role $role) 메서드를 사용합니다.
$role->revokePermissionTo($permission); $permission->removeRole($role);
HasRoles trait 사용
Eloquent model 에 HasRoles 트레이트를 연결했으면 직접 모델과 관련된 role 과 permission 을 사용할 수 있습니다.
다음은 id 가 1인 사용자에게 editor Role 을 부여합니다.
$role = Role::where('name', 'editors')->first(); $u = User::find(1); // 사용자에게 role 부여 $u->assignRole($role);
또는 user 에 직접 permission 을 연결해도 됩니다.
$u = User::find(1); $u->givePermissionTo(['create articles', 'edit articles']);
사용자에 부여된 role 삭제는 removeRole() 메서드를 사용하면 됩니다.
$u = User::find(1); $u->removeRole('editors');
Role 과 Permission 보유 여부
여러 Permission 을 Role 로 묶고 Role 을 User 별로 할당하는 것이 관리가 더 용이하므로 권장하고 있습니다.
이제 hasPermissionTo() 메서드로 해당 permission 을 갖고 있는지 확인할 수 있습니다.
$u = User::find(1); if ($user->hasPermissionTo('edit articles') === true) { dosomething(); }
별도로 지정하지 않았을 경우 기본 guard 는 web 이 됩니다.
web guard는 Illuminate\Auth\Access\Gate 에 권한이 등록되므로 can 메서드를 사용하는 것이 더 간편합니다.
$user->can('edit articles');
사용자의 Role 보유 여부는 hasRole() 메서드로 확인할 수 있습니다.
$user->hasRole('sys-admin'); // true or false
사용자가 보유한 전체 role 은 roles 매직 매서드로 확인할 수 있습니다.
$roles = $user->roles; // array of Role // Or $roles = $user->roles()->get();