应选用Spatie/laravel-permission而非手写RBAC,因其避免权限散落、角色权限耦合、表设计反复等问题,提供标准四表结构、缓存、中间件、Blade指令等开箱即用能力,专注解决“谁(用户)能做什么(权限)”这一核心问题。

为什么不用自己写RBAC而选Spatie/laravel-permission
自己实现RBAC容易陷入「权限判断散落各处」「角色与权限耦合过紧」「数据表设计反复推倒重来」的坑。Spatie/laravel-permission 已稳定维护多年,底层用的是标准的 roles、permissions、model_has_roles、role_has_permissions 四张表,不侵入 Eloquent 核心,且支持缓存、门面、中间件、Blade 指令等开箱即用能力。
它不是“大而全”的权限系统,而是专注解决「谁(用户)能做什么(权限)」这个核心问题——这点恰恰适合大多数 Laravel 项目。
安装后必须做的三件事
装完 composer require spatie/laravel-permission 后别急着写逻辑,先确认这三步已执行:
- 运行
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"发布迁移和配置 - 执行
php artisan migrate—— 注意:如果已有roles或permissions表,迁移会失败,需手动删表或改迁移名 - 在
User模型里添加use HasRoles;并确保该模型继承Illuminate\Foundation\Auth\User
漏掉第三点最常见:自定义用户模型没加 trait,调 $user->assignRole('admin') 会报 Call to undefined method assignRole()。
权限注册时机与命名规范
权限(Permission)是字符串,但不能随便写。比如 'edit posts' 和 'posts.edit' 看似等价,但实际影响可读性与扩展性。
推荐用 资源.动作 命名,例如:
Post.create Post.view Post.update Post.delete User.list User.export
这样既便于按模块归类,也方便后续做权限树展示或前端动态渲染菜单。注册方式有两种:
- 代码中一次性创建:
app/Providers/AppServiceProvider.php的boot()里用Permission::create(['name' => 'Post.create'])(仅开发期或 Seeder 中用) - 更稳妥的是写 Seeder:
php artisan make:seeder PermissionSeeder,然后在run()里批量插入,再执行php artisan db:seed --class=PermissionSeeder
切忌在控制器或中间件里边运行边创建权限——会导致数据库写入压力、重复插入异常、部署时权限丢失等问题。
中间件与 Blade 指令的实际用法
Spatie 提供了 role、permission、role_or_permission 三类中间件,但注意它们默认只校验当前用户,不支持传参(比如校验「是否拥有某文章的编辑权」这类行级权限需额外处理)。
常用写法示例:
- 路由组限制角色:
Route::middleware(['role:admin'])->group(...) - 单个路由限制权限:
Route::get('/posts/create', [PostController::class, 'create'])->middleware('permission:Post.create') - Blade 中控制按钮显示:
@can('Post.delete') @endcan(比@role('admin')更精准,推荐优先用@can)
容易忽略的一点:Laravel 的 @can 底层调用的就是 Spatie 的 can() 方法,所以只要模型用了 HasRoles,就能直接用;但如果在非用户模型(如后台管理员模型)上也要权限控制,得手动在该模型里加 HasRoles 并确保其对应的数据表有记录。










