必须通过rbac三表校验+redis缓存+中间件拦截实现权限控制:建auth_rule(rule_name唯一)、auth_role、auth_role_rule(联合主键+外键);permissioncheck中间件映射路由为rule_name并查redis缓存;登录/改权时生成或清除对应role_id缓存;前端按钮和菜单按user_rules动态渲染。

在ThinkPHP6.x后台管理系统中实现真正的权限拦截,必须让每个接口请求都经过角色-权限节点的实时校验,不能只靠登录态或角色名判断就放行。
三张核心数据表的设计与初始化
先建好 auth_rule、auth_role、auth_role_rule 三张表,字段和约束必须严格对齐RBAC运行逻辑。
执行 SQL 创建 auth_rule 表:包含 id、rule_name(【唯一且不可为空】)、title、type(menu/action)、status 字段,其中 rule_name 必须设为 UNIQUE 索引。
执行 SQL 创建 auth_role 表:仅需 id、name 两个字段,name 可重复但不建议,id 主键自增。
执行 SQL 创建 auth_role_rule 表:只有 role_id 和 rule_id 两个字段,联合主键,且各自加外键指向对应表——【缺一不可,否则中间件查关联会漏数据】。
插入初始超级管理员角色:INSERT INTO auth_role (name) VALUES ('super_admin');
插入基础权限节点:比如 admin.user.list、admin.user.edit、admin.menu.delete,type 设为 action;菜单节点如 admin.user.index 设为 menu。
PermissionCheck中间件的编写与挂载
在 app/admin/middleware/ 下新建 PermissionCheck.php,handle 方法内必须完成三件事:取当前路由名 → 映射为 rule_name → 查该用户角色所拥有的 rule_name 集合。
方法一:用 request()->rule()->getName() 获取原始路由规则名(如 admin/user/edit),再 str_replace('/', '.', $name) 转成 admin.user.edit 格式。
方法二:若路由用了资源路由或闭包定义,需额外兼容:检查 $request->action() 和 $request->controller() 拼接,例如 'admin.' . Str::snake($request->controller()) . '.' . $request->action()。
关键点:查权限时必须用 Redis 的 SMEMBERS 获取 cache('auth_rule_map_' . $roleId),而不是查数据库全量再 in_array——【否则高并发下数据库直接被打垮】。
挂载中间件到后台路由分组:在 app/route/app.php 中,对 admin 分组调用 ->middleware(\app\admin\middleware\PermissionCheck::class)。
权限缓存的生成与失效控制
第一步:用户登录成功后,在 AuthCheck 中间件的最后,调用 PermissionService::generateRoleRuleCache($roleId)。
第二步:该服务方法先查 auth_role_rule 表关联出所有 rule_id,再 JOIN auth_rule 表取出全部 rule_name,写入 Redis Set 结构 cache('auth_rule_map_' . $roleId),过期时间设为 1800 秒。
第三步:每次在角色管理中修改权限(增删 auth_role_rule 记录)时,必须同步执行 cache('auth_rule_map_' . $roleId, null) 清空对应缓存。
注意:不能清空全部角色缓存,也不能用通配符 DEL auth_rule_map_*——【否则其他角色权限会短暂失效】。
前端按钮级权限的渲染控制
在控制器里查出当前用户所有可用的 rule_name 列表,assign 给模板变量,例如 $this->assign('user_rules', $rules)。
在 layui-admin 的页面模板中,用 {{# if (user_rules.indexOf("admin.user.delete") > -1) { }} 包裹删除按钮标签。
这一步不能依赖后端跳转拦截——按钮必须从源头隐藏,否则懂审查元素的人能手动触发接口。
菜单栏同理:遍历菜单列表时,只渲染 rule_name 存在于 user_rules 中的项。
接口权限被绕过的紧急补救
如果发现 POST /admin/user/delete 接口未被拦截,立刻检查该路由是否被错误地注册在了未挂载 PermissionCheck 的路由分组下。
打开 app/route/app.php,确认该路由在 admin 分组内,且分组末尾有 ->middleware(\app\admin\middleware\PermissionCheck::class)。
检查中间件 handle() 方法结尾是否遗漏了 return $next($request) ——【漏掉这句会导致整个请求链中断,返回空白页而非 403】。
临时验证方式:在 handle() 开头加一行 Log::info('PermissionCheck triggered for ' . $ruleName),然后调接口看日志是否打出。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











