如何精简PostController中仅允许文章作者访问编辑页的权限判断代码?
优雅精简Laravel模型权限校验的几种方案
嘿,这个场景我太熟了!重复写这种“判断当前用户是否是资源所有者”的逻辑确实很冗余,Laravel给我们提供了几种非常优雅的解决方式,给你梳理一下最常用的几个:
1. 使用Laravel授权策略(Policy)—— 官方推荐的最佳实践
这是处理模型级权限控制的标准方式,不仅能精简控制器代码,还能在视图、命令行等其他地方复用权限逻辑。
步骤:
- 首先生成对应模型的策略文件:
php artisan make:policy VocabularyPolicy
- 在生成的
app/Policies/VocabularyPolicy.php里添加update方法(对应编辑/更新权限):
public function update(User $user, Vocabulary $vocabulary) { // 校验当前用户是否是词汇的所有者 return $user->id === $vocabulary->user_id; }
- 在
app/Providers/AuthServiceProvider.php中注册策略:
protected $policies = [ Vocabulary::class => VocabularyPolicy::class, ];
- 然后在控制器里就可以用一行代码完成校验:
public function edit(Vocabulary $vocabulary) { // 如果校验不通过,Laravel会自动抛出403异常,你也可以自定义响应 $this->authorize('update', $vocabulary); // 正常返回视图逻辑 return view('vocabularies.edit', compact('vocabulary')); }
- 更省心的方式:直接在路由层面绑定权限校验,不用碰控制器:
Route::get('/vocabularies/{vocabulary}/edit', [PostController::class, 'edit']) ->middleware('can:update,vocabulary');
2. 自定义中间件 —— 适合跨控制器的通用权限
如果多个控制器都需要类似的“资源所有者校验”,自定义中间件是个不错的选择。
步骤:
- 生成中间件:
php artisan make:middleware EnsureVocabularyBelongsToUser
- 在
app/Http/Middleware/EnsureVocabularyBelongsToUser.php里编写校验逻辑:
public function handle(Request $request, Closure $next) { // 从路由参数中获取词汇模型 $vocabulary = $request->route('vocabulary'); if ($vocabulary->user_id !== Auth::id()) { return redirect()->route('home')->with('danger', 'You cannot edit another user\'s vocabulary.'); } return $next($request); }
- 在
app/Http/Kernel.php的$routeMiddleware数组中注册中间件:
protected $routeMiddleware = [ // ...其他中间件 'vocab.owner' => \App\Http\Middleware\EnsureVocabularyBelongsToUser::class, ];
- 使用方式:
- 给单个路由添加:
Route::get('/vocabularies/{vocabulary}/edit', [PostController::class, 'edit'])->middleware('vocab.owner');- 给控制器指定方法批量添加(在控制器构造函数里):
public function __construct() { $this->middleware('vocab.owner')->only(['edit', 'update']); }
3. 控制器私有共享方法 —— 快速精简当前控制器代码
如果只是当前PostController里的几个方法需要这个校验,不想搞复杂的策略或中间件,直接写个私有方法复用就行。
实现:
在PostController里添加一个私有方法:
private function ensureOwnsVocabulary(Vocabulary $vocabulary) { if ($vocabulary->user_id !== Auth::id()) { return redirect()->route('home')->with('danger', 'You cannot edit another user\'s vocabulary.'); } }
然后在需要的方法里调用:
public function edit(Vocabulary $vocabulary) { $this->ensureOwnsVocabulary($vocabulary); // 返回视图... } public function update(Vocabulary $vocabulary) { $this->ensureOwnsVocabulary($vocabulary); // 更新逻辑... }
最后小建议
如果项目比较规范,优先用授权策略,它的扩展性最强,后续要加其他权限(比如删除、查看)也非常方便;如果是多个控制器共用的通用权限,选中间件;只是当前控制器用的话,私有方法最快捷。
内容的提问来源于stack exchange,提问作者entithat
相关产品推荐
相关产品推荐

