中间件注册必须加到 $routeMiddleware 并设别名,如 'role' => \App\Http\Middleware\Role::class;->middleware() 必须传数组,如 ['role:admin'];handle 方法需含 $roles 参数;User 模型须引入 HasRoles trait 并设置守卫名;权限缓存需手动重置,Gate 方法名须严格匹配。

中间件注册必须加到 $routeMiddleware,不能只写类路径
直接在 app/Http/Kernel.php 的 $routeMiddleware 数组里加别名,比如:'role' => \App\Http\Middleware\Role::class。
如果只在 $middleware 或 $middlewareGroups 里注册,路由用 ->middleware('role:admin') 会完全失效——框架根本找不到这个中间件别名。
->middleware() 传参必须是数组,字符串写法丢参数
这是最常踩的坑:写成 ->middleware('role:admin') 看似合理,但 Laravel 解析时会忽略冒号后所有内容,$roles 参数实际是 null。
✅ 正确写法只有两种:
->middleware(['role:admin'])->middleware(['role:admin|editor'])
handle() 方法签名也得匹配:public function handle($request, Closure $next, $roles) ——少这个参数,explode('|', $roles) 就会报错或静默失败。
User 模型没引入 HasRoles trait,所有权限方法都返回 false
装了 spatie/laravel-permission,跑了迁移,建了角色,但 $user->hasRole('admin') 始终是 false?大概率是 app/Models/User.php 里漏了两行:use Spatie\Permission\Traits\HasRoles;use HasRoles;
注意:不是在控制器里 use,必须挂载到模型类上。如果用了多守卫(比如 admin),还得显式调用 HasRoles::setGuardName('admin'),否则默认查 web 守卫下的角色关系。
权限检查别在中间件里实时查库,缓存没重置会导致权限不生效
每次请求都走 $user->roles()->get() 或手写 SQL 查权限,TTFB 会飙升;而用了 Spatie 包却忘了 php artisan permission:cache-reset,新分配的权限就永远不生效——它不会自动刷新缓存。
缓存重建只发生在第一次 $user->can() 调用之后,别误以为逻辑错了。另外,Gate 定义和 Policy 方法名要严格对应:can('delete-post') 对应的是 deletePost() 或 delete_post(),写成 destroy() 就直接抛 BadMethodCallException。


















