PHP权限管理核心是四表结构(users、roles、permissions、role_permissions)+用户角色关联表user_roles,权限码唯一索引,登录后缓存至Redis并由角色变更主动失效,can()方法仅做内存比对,严格对齐路由与权限code。

PHP 权限管理不是配个中间件就能跑通的事,核心卡点在「权限判定必须快、关系建模不能冗余、缓存和数据库必须严格对齐」。跳过这三点,轻则 403 随机出现,重则权限变更后数小时不生效。
怎么建表才不会查不出权限
最小可用结构就是 4 张表:users、roles、permissions、role_permissions。别加 permission_group、role_hierarchy 这类字段——90% 的内部系统根本用不到层级继承,加了反而让 JOIN 变慢、迁移变难。
-
permissions表的code字段必须加UNIQUE索引,否则重复插入时无报错,查重全靠 PHP 数组去重,性能崩得悄无声息 -
role_permissions必须是联合主键(role_id, permission_id),且两个外键分别指向roles.id和permissions.id;千万别用 JSON 字段存权限列表,等于主动放弃外键约束和WHERE role_id = ?的索引加速 - 用户多角色场景下,
users表里不要加role_id字段,另建user_roles表(字段为user_id、role_id),否则扩展性归零
为什么每次请求都查库=自毁性能
典型错误是写个 getPermissionsByUserId($userId),每次进控制器就 JOIN 四张表。QPS 上去后,数据库连接池先扛不住。
- 登录成功后,立刻查出该用户所有角色对应的全部
permissions.code,返回纯字符串数组,例如['post:create', 'order:read'] - 缓存进 Redis,key 形如
"user_perms_{$userId}_v2",TTL 设为 60 秒;角色变更时,同步删掉这个 key - 如果用 Laravel,
User模型里加permissions()关联,但一定要链式调用->pluck('code'),否则加载的是整行Permission对象,内存和序列化开销翻倍
can() 方法里到底该查什么
can($permissionCode) 必须是纯内存比对,不是查库、不是查 Redis、更不是重新 JOIN。它的输入源只能是上一步缓存好的权限数组。
立即学习“PHP免费学习笔记(深入)”;
- 中间件里调用
$request->user()->can('post:delete')前,确保User实例已预加载权限数组到属性里(比如$this->cachedPermissions) - 别在 Blade 模板里写
@if(auth()->user()->can('user:export')),view 层只负责渲染,权限逻辑必须下沉到 service 或中间件 - 路由和权限 code 要保持一致:如果路由定义是
admin/user/list,那权限码就得是admin/user/list,不是user:list也不是admin.user.list,否则中间件永远返回 false
最易被忽略的一点:权限缓存失效时机不是靠 TTL 等着过期,而是靠「角色变更操作」触发主动删除。没人手动删 key,缓存就永远 stale——前端按钮还灰着,后端其实早开了权限。



















