Spatie Permission:多角色权限管理
High Contrast
Dark Mode
Light Mode
Sepia
Forest
1 min read211 words

Spatie Permission:多角色权限管理

Laravel 原生的 Gate/Policy 是代码驱动的——改权限需要改代码。spatie/laravel-permission 把角色和权限存到数据库,可以在运行时动态调整,是构建 SaaS 后台管理系统的标准选择。


安装

composer require spatie/laravel-permission
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"
php artisan migrate
# 创建:roles, permissions, model_has_roles, model_has_permissions, role_has_permissions 表
// app/Models/User.php
use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable, HasRoles;
}

核心操作

use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;
// 创建角色和权限
$adminRole  = Role::create(['name' => 'admin']);
$memberRole = Role::create(['name' => 'member']);
$viewerRole = Role::create(['name' => 'viewer']);
Permission::create(['name' => 'tasks.create']);
Permission::create(['name' => 'tasks.delete']);
Permission::create(['name' => 'billing.manage']);
// 给角色分配权限
$adminRole->givePermissionTo(['tasks.create', 'tasks.delete', 'billing.manage']);
$memberRole->givePermissionTo(['tasks.create']);
$viewerRole->syncPermissions([]);  // 无任何权限
// 给用户分配角色
$user->assignRole('member');
$user->assignRole(['member', 'viewer']);  // 多角色
// 给用户直接分配权限(绕过角色)
$user->givePermissionTo('billing.manage');
// 撤销
$user->removeRole('member');
$user->revokePermissionTo('billing.manage');

检查权限

// 检查角色
$user->hasRole('admin');
$user->hasAnyRole(['admin', 'manager']);
$user->hasAllRoles(['admin', 'moderator']);
// 检查权限(包括通过角色继承的权限)
$user->hasPermissionTo('tasks.create');
$user->can('tasks.delete');                 // Laravel 原生 can(),与 Spatie 兼容
$user->cannot('billing.manage');
// 获取用户的所有权限(含角色继承)
$user->getAllPermissions();
// 在控制器中使用
public function destroy(Task $task)
{
abort_if(!auth()->user()->can('tasks.delete'), 403);
$task->delete();
}
// 在路由中使用中间件
Route::middleware('permission:billing.manage')->group(function () {
Route::get('/billing', [BillingController::class, 'index']);
});
Route::middleware('role:admin')->group(function () {
Route::get('/admin', [AdminController::class, 'index']);
});
// 同时检查角色或权限
Route::middleware('role_or_permission:admin|billing.manage')->group(fn() => /* ... */);

注册中间件别名(Laravel 11)

// bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
$middleware->alias([
'role'               => \Spatie\Permission\Middleware\RoleMiddleware::class,
'permission'         => \Spatie\Permission\Middleware\PermissionMiddleware::class,
'role_or_permission' => \Spatie\Permission\Middleware\RoleOrPermissionMiddleware::class,
]);
})

在 Blade 模板中使用

@role('admin')
<a href="/admin">管理控制台</a>
@endrole
@hasrole('admin|manager')
<button>删除</button>
@endhasrole
@can('tasks.create')
<a href="/tasks/create">新建任务</a>
@endcan
@unlesshaspermission('billing.manage')
<p>升级到 Premium 解锁更多功能</p>
@endunlesshaspermission

TaskFlow 完整权限矩阵

// database/seeders/RolePermissionSeeder.php
public function run(): void
{
app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();
// 定义所有权限
$allPermissions = [
'tasks.create', 'tasks.read', 'tasks.update', 'tasks.delete',
'projects.create', 'projects.read', 'projects.update', 'projects.delete',
'team.invite', 'team.manage',
'billing.read', 'billing.manage',
'admin.users', 'admin.settings',
];
foreach ($allPermissions as $perm) {
Permission::firstOrCreate(['name' => $perm]);
}
// 角色权限矩阵
$roles = [
'admin'   => $allPermissions,  // 所有权限
'manager' => ['tasks.create', 'tasks.read', 'tasks.update', 'tasks.delete',
'projects.create', 'projects.read', 'projects.update',
'team.invite', 'billing.read'],
'member'  => ['tasks.create', 'tasks.read', 'tasks.update',
'projects.read'],
'viewer'  => ['tasks.read', 'projects.read'],
];
foreach ($roles as $roleName => $permissions) {
$role = Role::firstOrCreate(['name' => $roleName]);
$role->syncPermissions($permissions);
}
}

性能优化:缓存

Spatie Permission 默认使用 Laravel Cache 缓存权限数据(默认 24 小时):

// 手动清除权限缓存(修改权限后调用)
app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();
// 或用 Artisan 命令
php artisan permission:cache-reset
// config/permission.php 中自定义缓存时间
'cache' => [
'expiration_time' => \DateInterval::createFromDateString('24 hours'),
'key'  => 'spatie.permission.cache',
'store' => 'default',
],

下一章队列、Job 与异步任务——权限系统搭建好了,下一个关键技能是队列。发邮件、处理图片、同步第三方 API——这些耗时操作都不应该在 HTTP 请求中同步执行。