thinkphp后台模块目录必须手动创建,不能仅靠路由配置;app/admin/需含controller/、model/等子目录,模块名须全小写加下划线,多应用模式下路径为app/admin/controller/user.php,rbac权限校验依赖auth_rule表及严格匹配的rule_name。

ThinkPHP后台模块目录必须手动建,不能只靠路由配置
后台入口不是靠访问 /admin 自动触发的——app/admin/ 目录不存在,哪怕 route.php 里写了 Route::get('admin/user/list', 'admin/user/list'),照样 404。框架不会扫描子目录“猜”模块。
实操要点:
-
app/admin/目录必须手动创建,且至少含controller/、model/、config.php(可选) - 模块名只能是全小写+下划线,
user-center是非法名,会报Invalid module name - 启用多应用模式时路径是
app/admin/controller/User.php;单应用模式下若没配app_multi = true,该路径反而会找不到类 - 模块间控制器不能裸
new \app\admin\controller\User()——模型绑定、中间件、请求上下文全失效
RBAC权限节点表结构不能省掉 auth_rule 表
只建 auth_role 和 auth_role_rule 两张表,漏掉 auth_rule,就等于把权限压缩成「角色-菜单」二元关系。结果是:能控制用户看到哪个页面,但拦不住 POST /admin/user/delete 这种接口请求。
关键字段必须有:
-
rule_name:唯一标识,小写+点号分隔,如admin.user.delete,不能用中文或 ID -
type:区分menu(前端菜单)和action(后端接口),中间件只校验action类型节点 -
status:启用/禁用开关,避免删数据,方便灰度 -
auth_role_rule.rule_id必须是外键关联auth_rule.id,别用字符串拼接或 JSON 存 rule_name
中间件里查权限不能查全量,必须按 role_id 缓存
在中间件里每次请求都 SELECT * FROM auth_role_rule WHERE role_id = ?,数据库扛不住;更不能把所有角色的权限塞进一个缓存 key 里,否则 A 角色删了权限,B 角色还在用旧缓存,直接越权。
正确做法是:
- 用
request()->rule()->getName()拿到当前路由规则名(如admin/user/delete),映射为admin.user.delete - 缓存 key 设为
auth_rule_map_{$roleId},值为 Redis Set 结构,存该角色拥有的全部rule_name - 缓存未命中时,查
auth_role_rule JOIN auth_rule,生成 Set 并写入,过期时间设为 30 分钟 - 权限变更时,必须主动执行
cache('auth_rule_map_'.$roleId, null)清空对应缓存
Auth::check() 和 $this->auth->hasRole() 根本不校验 RBAC 节点
这两个方法只回答「用户是否登录」和「用户是否属于某角色」,完全不碰 auth_rule 表。典型现象:按钮前端隐藏了,但用户手动发个 curl -X POST /admin/user/delete,接口照样执行成功——因为中间件根本没挂载到这个路由上。
排查重点:
- 确认中间件已注册到
app/middleware.php的全局或分组中间件列表中 - 中间件顺序必须在
SessionInit之后,否则拿不到 session 中的role_id - 检查路由是否被分组包裹,比如
Route::group('api', ...),那中间件也得加到该分组内才生效 - TP6 的
think\facade\Auth不支持 RBAC,别指望它自动拦截——你写的中间件才是唯一防线
最常被忽略的一点:rule_name 和路由定义必须严格对齐。你写 Route::post('admin/user/del', 'UserController@delete'),节点就必须是 admin.user.del,而不是 admin.user.delete 或 user_delete。错一个字符,缓存查不到,中间件就放行。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











