Laravel权限判断缓存有五种方法:一、Gate缓存装饰器;二、Policy局部缓存;三、Authorization Cache中间件;四、Redis细粒度缓存表;五、禁用动态策略反射。

如果您在 Laravel 应用中频繁调用 Gate::allows() 或 @can 指令进行权限判断,而底层策略或能力逻辑涉及数据库查询或复杂计算,则每次请求都重复执行会带来显著性能开销。以下是为权限判断结果实施安全缓存的多种方法:
一、使用 Laravel 自带的 Gate 缓存装饰器
通过封装 Gate 实例,对 can/abilities 方法的返回值进行键值化缓存,避免重复评估同一用户对同一能力的判断。缓存键需包含用户 ID、能力名、相关模型实例哈希及策略版本标识,确保安全性与一致性。
1、创建 App\Providers\CachedGateServiceProvider.php,在 register() 中绑定自定义 Gate 实例。
2、在 bind() 中使用 Cache::remember() 包裹 Gate::forUser()->allows() 调用,缓存有效期设为 30 分钟。
3、为防止越权,缓存键中嵌入 Auth::id() 与 $ability,并对 $arguments 使用 serialize() 后取 sha256 哈希作为子键。
4、在 config/auth.php 的 guards 配置中启用 session 驱动,并确保 cache driver 支持原子操作(如 redis)。
二、基于 Policy 类的局部结果缓存
在自定义 Policy 方法内部手动控制缓存读写,仅对确定无副作用、不依赖运行时上下文(如 request()->ip() 或当前时间)的能力逻辑启用缓存,规避策略状态污染风险。
1、在 Policy 方法开头构造唯一缓存键:'policy_'.get_class($this).'_'.md5($user->id.$ability.json_encode($arguments))。
2、使用 Cache::get($key) 尝试获取缓存值,若存在且为布尔类型则直接 return。
3、若未命中,执行原始权限逻辑,得到 $result 后调用 Cache::put($key, $result, now()->addMinutes(15))。
4、在用户角色变更、权限分配更新时,通过事件监听器触发 Cache::delete($key) 或使用通配符清除(需 Redis 支持)。
三、利用 Laravel 的 Authorization Cache 中间件
针对控制器方法级权限校验,编写中间件在进入控制器前预加载并缓存当前用户全部可访问能力列表,后续 @can 判断转为数组 in_array 查找,消除重复 Gate 调用。
1、创建中间件 App\Http\Middleware\CacheUserAbilities,handle() 中调用 Gate::abilities() 获取所有能力名数组。
2、将该数组以 'abilities_user_'.$user->id 为键存入缓存,设置 TTL 为 10 分钟。
3、重写 Blade 指令 @can,使其优先从 $app->make('cache')->get('abilities_user_'.Auth::id()) 中查找能力名是否存在。
4、在用户权限变更事务提交后,同步删除对应用户的 abilities 缓存项,确保缓存失效时机与 DB 更新强一致。
四、基于 Redis 的细粒度权限缓存表
构建独立缓存结构,以 user_id:ability:model_type:model_id 为键,存储布尔值,支持模型实例级精确缓存,适用于 hasPermissionTo 等 Scout 或 Spatie 权限包集成场景。
1、在检查权限前,先拼接 Redis 键:sprintf('perm:%d:%s:%s:%s', $user->id, $ability, $model?->getMorphClass(), $model?->getKey())。
2、使用 Redis::command('EXISTS', [$key]) 快速探查,若存在则执行 Redis::get($key) 并 cast 为 boolean。
3、若未命中,执行原始权限判定,随后调用 Redis::setex($key, 1800, (int)$result),TTL 设为 30 分钟。
4、监听模型事件如 PermissionAttached、RoleUpdated,在事件处理器中批量删除匹配 perm:*:$user_id:* 的所有键,防止因通配符扫描导致 Redis 阻塞。
五、禁用动态策略反射,强制预编译缓存
关闭 Gate 默认的动态策略解析机制,改用静态映射配置,使所有能力到策略类的绑定在应用启动时固化,避免每次请求都触发 class_exists() 和反射开销,间接提升缓存命中率稳定性。
1、在 AuthServiceProvider 的 boot() 中调用 Gate::guessPolicyNamesUsing(null) 彻底禁用自动策略发现。
2、显式注册所有能力:Gate::define('update-post', [PostPolicy::class, 'update'])。
3、将完整映射关系导出为 config/gate_policy_map.php 静态数组,供缓存层初始化时加载。
4、在部署流程中加入 artisan config:clear && php artisan gate:cache 命令,生成序列化策略映射文件,杜绝运行时反射调用带来的不可控缓存穿透。










