应选用Spatie/laravel-permission而非手写RBAC,因其避免权限散落、角色权限耦合、表设计反复等问题,提供标准四表结构、缓存、中间件、Blade指令等开箱即用能力,专注解决“谁(用户)能做什么(权限)”这一核心问题。
为什么不用自己写RBAC而选Spatie/
laravel
-permission
自己实现RBAC容易陷入「权限判断散落各处」「角色与权限耦合过紧」「数据表设计反复推倒重来」的坑。Spatie/laravel-permission 已稳定维护多年,底层用的是标准的
、
、
、
四张表,不侵入 Eloquent 核心,且支持缓存、门面、中间件、Blade 指令等开箱即用能力。
它不是“大而全”的权限系统,而是专注解决「谁(用户)能做什么(权限)」这个核心问题——这点恰恰适合大多数 Laravel 项目。
安装后必须做的三件事
装完
后别急着写逻辑,先确认这三步已执行:
运行
发布迁移和配置
执行
—— 注意:如果已有
或
表,迁移会失败,需手动删表或改迁移名
在
模型里添加
并确保该模型继承
漏掉第三点最常见:自定义用户模型没加 trait,调
会报
。
权限注册时机与命名规范
权限(
)是字符串,但不能随便写。比如
和
看似等价,但实际影响可读性与扩展性。
推荐用
命名,例如:
Laravel 13.2.0
PHP中文网提供Laravel 13.2.0版本下载,Laravel框架 是基于 PHP 8.3+ 的高性能框架,官方推荐通过 Composer 安装。它内置 AI SDK、JSON:API Resources 及原生向量搜索,支持属性驱动开发与队列路由,大幅提升开发效率。相比旧版,13.2.0 优化了缓存 TTL 管理与实时通信,无需 Redis 即可横向扩展。作为现代 Web 开发首选,它兼顾安全与极速体验,助您快速构建企业级应用。
下载
这样既便于按模块归类,也方便后续做权限树展示或前端动态渲染菜单。注册方式有两种:
代码中一次性创建:
的
里用
(仅开发期或 Seeder 中用)
更稳妥的是写 Seeder:
,然后在
里批量插入,再执行
切忌在控制器或中间件里边运行边创建权限——会导致数据库写入压力、重复插入异常、部署时权限丢失等问题。
中间件与 Blade 指令的实际用法
Spatie 提供了
、
、
三类中间件,但注意它们默认只校验当前用户,不支持传参(比如校验「是否拥有某文章的编辑权」这类行级权限需额外处理)。
常用写法示例:
路由组限制角色:
单个路由限制权限:
Blade 中控制按钮显示:
(比
更精准,推荐优先用
)
容易忽略的一点:Laravel 的
底层调用的就是 Spatie 的
方法,所以只要模型用了
,就能直接用;但如果在非用户模型(如后台管理员模型)上也要权限控制,得手动在该模型里加
并确保其对应的数据表有记录。
rolespermissionsmodel_has_rolesrole_has_permissionscomposer require spatie/laravel-permissionphp artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"php artisan migraterolespermissionsUseruse HasRoles;Illuminate\Foundation\Auth\User$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.phpboot()Permission::create(['name' => 'Post.create'])php artisan make:seeder PermissionSeederrun()php artisan db:seed --class=PermissionSeederrolepermissionrole_or_permissionRoute::middleware(['role:admin'])->group(...)Route::get('/posts/create', [PostController::class, 'create'])->middleware('permission:Post.create')@can('Post.delete') @endcan@role('admin')@can@cancan()HasRolesHasRoles