使用spatie/laravel-permission需为后台单独配置admin守卫、provider、模型及策略,确保guard_name一致;菜单渲染应预加载权限并缓存角色映射,避免N+1查询与静默失效。

用 spatie/laravel-permission 快速搭多角色后台
它不是 Laravel 自带的,但已经是事实标准——不用自己手写角色表、权限中间表、守卫逻辑。装完就能给不同管理员分配不同菜单和操作权限。
常见错误现象:Auth::user()->can('delete user') 一直返回 false,但数据库里明明加了权限;或者 Gate::inspect 报 Undefined index: guard_name。
- 必须在
config/auth.php的guards下为后台单独配一个守卫(比如叫admin),不能复用web守卫 -
Permission和Role模型默认绑定webguard,要改$guard_name属性,或在迁移里指定guard_name字段值为'admin' - 给用户赋角色时用
$user->assignRole('super-admin'),不是$user->roles()->attach(...)—— 后者绕过包的缓存和事件,容易权限不生效
Laravel 后台路由如何隔离 admin 和 web 中间件
很多人把后台路由塞进 web 中间件组,结果登录态串了:前台用户登着登着进了后台首页。本质是 Session 和 Guard 混用。
使用场景:需要独立登录页、独立密码重置流程、独立 remember_token 存储位置。
- 在
app/Http/Kernel.php的$middlewareGroups['admin']里定义专属中间件栈,至少包含EncryptCookies、StartSession、Authenticate:admin -
routes/admin.php必须用Route::middleware('admin')包裹,而不是web -
config/auth.php中guards.admin.provider要指向专为后台建的admin_users用户表(别用users表混用)
can() 判断失效?检查模型策略是否绑对了守卫
权限判断失败最常卡在这儿:策略类没声明用哪个 guard,Laravel 默认走 web,而你的管理员走的是 admin guard。
错误现象:Auth::guard('admin')->user()->can('update', $post) 返回 true,但 Blade 里 @can('update', $post) 却不显示按钮。
- 策略类的
__construct()不用管,重点是boot()或服务提供者里注册时,显式传admin: -
Gate::resource('post', PostPolicy::class)->middleware('auth:admin')—— 这行不能少 - 或者在
AuthServiceProvider@boot里用Gate::define('update post', function ($user, $post) { ... }),里面直接用$user->hasRole('editor')手动判断,避开 guard 自动解析
菜单动态渲染时权限校验别只查 can(),得结合 role
后台左侧菜单如果只靠 @can('view dashboard') 控制显隐,会漏掉“有权限但没分配角色”的边界情况。更稳妥的是先确认用户属于哪个角色组,再查该角色下所有权限。
性能影响:每次请求都查一次 roles + role_has_permissions 关联表,建议加 Redis 缓存角色权限映射。
- 不要在 Blade 里循环每个菜单项都调一次
@can—— 会 N+1 查询,改用预加载:$user->load('roles.permissions')在控制器里一次性取全 - 菜单配置建议抽成 PHP 数组(如
config/menu.php),每项带'permission' => 'view_reports'或'role' => ['admin', 'auditor'],渲染时统一过滤 - 注意:超级管理员(
hasRole('super-admin'))应跳过所有权限检查,但这个判断本身也要走缓存,否则每次点菜单都查一次数据库
真正麻烦的不是装包或写路由,而是 guard、provider、model、policy 四者之间的守卫名必须完全一致,错一个字母,权限就静默失效。调试时优先 dump Auth::guard('admin')->user()?->getGuardName() 和 config('auth.guards.admin.guard') 看是不是真的一样。


















