应优先查Redis校验权限,键名用app_name:user:perms:{uid}格式,登录/权限变更时主动写入并设3600秒过期,失效时立即del,避免混用ThinkPHP缓存门面与原生Redis客户端。

权限校验前先查 Redis 而不是数据库
每次请求都查数据库判断用户是否有某个 permission_code,性能会随并发陡增而崩。Redis 作为内存存储,毫秒级响应,适合存「用户ID → 权限码列表」这种结构化小数据。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 用户登录/权限变更后,主动写入 Redis:
$redis->setex('user:perms:'.$uid, 3600, json_encode($permList)) - 校验时只读不写:
$perms = json_decode($redis->get('user:perms:'.$uid), true),再用in_array('post:delete', $perms)判断 - 别用 Hash 存整个权限树——ThinkPHP 的
Auth类默认不支持自动解析 Hash 字段,容易误判 - 缓存过期时间设为 3600 秒(1 小时)比永不过期更安全:权限调整后最多延迟 1 小时生效,避免线上误放行
Redis 键名设计要带业务前缀和可读性
键名乱写会导致清理困难、跨环境冲突,比如直接用 perms_123,测试服和生产服 Redis 混用时会互相覆盖。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 统一用
app_name:user:perms:{uid}格式,例如cms:user:perms:456 - 避免在键里拼接角色名或部门 ID——权限是用户维度的,不是角色维度的;角色变更应触发对应用户缓存更新,而非另建一套键
- 不要用
serialize()存值:PHP 版本升级或类结构变动会导致unserialize()失败,json_encode()更稳 - 上线前用
redis-cli --scan --pattern 'cms:user:perms:*' | wc -l快速确认缓存规模,超 10 万条要考虑分片或改用布隆过滤器预检
权限变更时必须主动失效缓存,不能依赖过期
管理员后台修改某用户权限后,如果只等 Redis 自动过期,期间可能出现「已禁用但还能操作」的安全漏洞。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 在权限分配/回收逻辑末尾加一行:
$redis->del('cms:user:perms:'.$uid) - 如果是批量操作(如给部门全员加权限),用 pipeline 批量删:
$redis->pipeline()->del(...array_map(fn($u) => 'cms:user:perms:'.$u, $uids))->execute() - 别在中间件里「静默兜底」:有些同学会在权限校验失败时自动回查 DB 并写缓存,这会掩盖真实问题,且可能把错误权限写进 Redis
- 测试时重点验证「改完立刻生效」:前端调接口前清掉本地 Cookie,用新请求验证,而不是刷页面看 UI 是否变灰
ThinkPHP 6 的 Cache::store('redis') 不等于直连 Redis
默认配置下,Cache::store('redis') 实际走的是 ThinkPHP 自封装的缓存驱动,它会对 key 加前缀、对 value 序列化,和原生 Predis\Client 行为不一致——混用会导致「写进去读不出」。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 权限缓存建议绕过
Cache门面,直接 new 一个Predis\Client实例(配好tcp://127.0.0.1:6379),确保读写行为可控 - 如果坚持用
Cache,必须统一用Cache::tag('permission')->set(...),否则 tag 清理机制无法匹配到你写的 key - 检查
config/cache.php中 redis 驱动的prefix配置是否为空字符串——非空会导致键名变成think_cache:cms:user:perms:123,和其他服务不兼容 - 本地开发用
phpredis扩展,线上用Predis时注意scan命令返回格式差异,权限预热脚本要适配
最常被忽略的一点:Redis 连接池没配超时,高并发下连接堆积,权限校验卡在 connect() 阶段,表现就是偶发 504——这不是缓存逻辑问题,是基础设施没兜住。



















