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();



Ref