Laravel 授权实战:用 Policy 与 Gate 把权限判断收口到一处

test12026-09-303 次阅读

为什么要把授权收口

权限判断如果散落在控制器、模板、服务里,规则一变就要到处改,还容易漏。Laravel 提供 Gate 和 Policy 两套机制,把「当前用户能不能做这件事」集中定义,调用方只管问一句 authorize,通过才继续,否则自动抛 403。

用 Gate 注册闭包式授权

简单场景用 Gate 在服务提供者里注册一个闭包即可,第一个参数是当前用户,后面是业务参数。

// app/Providers/AppServiceProvider.php
use App\Models\Post;
use Illuminate\Support\Facades\Gate;

public function boot(): void
{
    Gate::define('update-post', function ($user, Post $post) {
        return $user->id === $post->user_id;
    });
}

用 Policy 绑定模型

模型相关的授权更适合写成 Policy,一个模型一套方法,可读性更好。用 artisan 命令生成并绑定模型。

// php artisan make:policy PostPolicy --model=Post
namespace App\Policies;

use App\Models\Post;
use App\Models\User;

class PostPolicy
{
    public function update(User $user, Post $post): bool
    {
        return $user->id === $post->user_id;
    }

    public function delete(User $user, Post $post): bool
    {
        return $user->is_admin || $user->id === $post->user_id;
    }
}

在控制器里使用

控制器里一行 authorize 就能挡住越权请求,未通过会直接抛出 AuthorizationException(框架转成 403)。

public function update(Request $request, Post $post)
{
    $this->authorize('update', $post); // 不通过直接抛 403
    // 通过后再执行业务逻辑
    $post->update($request->validated());
    return redirect()->back();
}

在模板里做条件渲染

Blade 提供了 @can 指令,让用户只能看到自己有权限操作的按钮,避免「点了才报错」的体验。

@can('delete', $post)
    <button>删除</button>
@endcan

几点注意

  • Gate 适合与具体模型无关的通用能力,Policy 适合绑定到某个模型的细粒度操作。
  • authorize 第二个参数传模型实例,Laravel 会自动解析出对应的 Policy。
  • 管理员兜底逻辑写在 Policy 里比写在控制器更统一,避免每个方法都单独判断。
  • API 场景下用 abort(403) 或异常处理器统一返回 JSON 错误体,不要让前端拿到整页错误。
T

test1

文章作者

为什么要把授权收口 权限判断如果散落在控制器、模板、服务里,规则一变就要到处改,还容易漏。Laravel 提供 Gat...

分类
技术
发布时间
2026-09-30
字数
约 1510 字
阅读
3 次