权限节点必须用rule_name(如admin.user.edit)作唯一标识,不能用中文名或ID;三表结构为auth_rule、auth_role、auth_role_rule;中间件需按需查缓存校验节点,权限变更须主动清理对应role_id缓存。

权限节点必须用 rule_name 做唯一标识,不是中文名也不是 ID
TP6 的 RBAC 能不能跑通,第一步就卡在这儿:所有权限节点(比如「编辑用户」)必须存为小写+点号分隔的字符串,如 admin.user.edit,而不是「用户编辑」或数字 ID。中间件靠它匹配路由,前端按钮也靠它做显隐控制。一旦用中文或 ID 当判断依据,后续所有拦截、缓存、菜单渲染都会失效。
常见错误是把 auth_rule 表设计成「菜单-角色」二元关系,漏掉操作节点层——结果页面能进,但 POST /admin/user/delete 这种接口请求根本拦不住。
-
rule_name必须和路由定义严格对齐:Route::get('admin/user/list', ...) → 节点名就是admin.user.list,不是user_list或/admin/user/list - 多应用(如
admin和api)下,rule_name前缀必须带应用名,否则权限会串 -
type字段建议只分menu和permission两类:前者给前端渲染菜单,后者给后端校验接口
中间件里怎么查权限才不拖慢请求
别在中间件里每次请求都查数据库再 in_array() 判断——TP6 没内置 RBAC 支持,得自己搭链路。更别把全量权限塞进 Session,一改权限就得清空所有用户登录态。
实操走「按需查 + 缓存兜底」:先用 $request->rule()->getName() 拿当前路由规则名(如 admin/user/edit),转成标准 rule_name 格式;再查 Redis 缓存 auth_rule_map_{$roleId}(Set 结构);没命中才查 auth_role_rule 关联表生成并写入,过期设 30 分钟。
- 缓存 key 必须含
role_id,不能只缓存全量节点,否则 A 角色删了权限、B 角色缓存未过期,就会误放行 - 游客直接跳登录页,超管(
is_super = 1)短路放行,别让超管也走一遍权限扫描 - 中间件注册位置必须靠后:放在
app/middleware.php的'http'数组里,且在SessionInit之后、业务控制器之前
getTree() 递归构造权限树时容易踩的坑
给角色配置权限页面用的树形结构,核心是 getTree($node, $access, $pid) 这个递归函数。它本身不复杂,但数据准备不对就白搭。
$node 是全部权限节点列表,$access 是该角色已绑定的 node_id 数组。递归前必须确保:pid 字段是 int 类型且允许 NULL 或 0;若设成 varchar,递归可能无限循环或报错;$node 中每个元素必须有 id 和 pid,缺一不可。
- 别在
auth_rule表里滥用condition字段:每次Auth::check()都要拼 SQL 执行,极易全表扫描甚至 SQL 注入 -
status、sort、remark等字段尽量别加,TP 权限判定只依赖name和type,字段越多 JOIN 越慢 - 前端渲染菜单时,只读
type = 'menu'的节点;按钮级权限校验只认type = 'permission'
为什么按钮显示了却点不了,或者接口 403 但日志没报错
这不是中间件没生效,而是前后端权限名没对齐。LayUI 后台常见现象:菜单能展开、按钮能渲染,但点击后接口返回 403 却没日志——说明后端拦截成功了,但前端传的权限标识和后端 rule_name 不一致。
排查重点不在代码逻辑,而在三处对齐:
- 前端按钮指令(如 LayUI 的
lay-auth="admin.user.delete")中的字符串,必须和auth_rule.name完全一致(包括大小写、点号、前缀) - 路由定义是否用了
->name('xxx')?如果用了,$request->rule()->getName()返回的就是这个 name;没用的话,它可能返回空或反射路径,此时不能依赖它生成权限名 - 登录后是否调用
Auth::setUser($uid)?TP6 的Auth::check()默认从session('think_auth')读缓存,这个 session 不是自动写的,漏掉这步,权限永远是 false
最隐蔽的坑是中间件函数没显式 return:校验通过时必须 return $next($request),否则函数末尾隐式返回 null,框架当成中断处理——请求直接断掉,连 403 都不会返回。


















