Laravel策略类需手动注册到Gate才能生效,未注册时authorize()直接返回false或403;必须在AuthServiceProvider中调用Gate::policy(Post::class, PostPolicy::class),并使用$this->authorize()而非Gate::allows(),且确保模型实例已预加载关联数据。
策略类写好了但没生效,不是逻辑错了,而是它根本没被调用——Laravel 不会自动注册或扫描 Policy,必须手动绑定、走对调用路径、传对参数。
Policy 必须显式注册到 Gate 才能触发
放在
目录下、类名是
,Laravel 也不会自动认。不注册,
就不会进你的方法,而是直接返回 false 或抛出 403。
在
的
方法里加:
确保顶部已引入:
和
改完记得清缓存:
,否则旧注册可能还在生效
控制器里要用
,别手写
是绕过策略解析的“裸调用”,它只查你用
定义的闭包,不会自动匹配
。而
才会根据模型类查注册表,再反射调用对应 Policy 方法。
正确写法:
(自动识别
→
)
资源控制器可一步到位:
,但要求路由参数名是
、方法参数是
自定义方法名(如
)必须显式调用:
,不能简写
Policy 方法里拿不到关联数据?不是 Policy 的问题
常见现象:
是 null,或
报错 —— 这说明传进来的
实例本身字段不全,或者关系没预加载。
Policy 不做查询,只处理“已查出”的模型实例。控制器里得提前
或
避免在 Policy 里写
,这会触发隐式 N+1 查询,也违背职责分离
若需判断是否已加载关系,用
先兜底,别直接访问
复杂条件(如时间窗口、角色组)应抽到模型方法里,Policy 只留布尔调用,例如:
真正容易被忽略的是:Policy 生效与否没有日志、不报错、也不提示。调试时第一反应不该是“逻辑写错了”,而是先确认
是否执行了、
是否真把模型传进去了、
实例里到底有啥字段——用
看一眼最实在。
app/Policies/PostPolicy$this->authorize('update', $post)app/Providers/AuthServiceProvider.phpboot()Gate::policy(Post::class, PostPolicy::class);use App\Models\Post;use App\Policies\PostPolicy;php artisan config:clear$this->authorize()Gate::allows()Gate::allows('update', $post)Gate::define()PostPolicy::update()$this->authorize()$this->authorize('update', $post);PostPostPolicy$this->authorizeResource(Post::class);{post}Post $postcanPublishDraft$this->authorize('canPublishDraft', $post)$post->user_id$post->author->is_admin$postwith('author')load('author')$post->user->is_admin$post->relationLoaded('author')return $user->inEditorGroup() || $post->isEditableWithinTimeframe();Gate::policy()$this->authorize()$postdd($post->toArray())