简介
本文件面向 DouPHP 后台权限分配系统,聚焦“基于角色的权限分配机制”,覆盖菜单、按钮、API 接口的精细化控制;说明权限树构建算法、继承规则与冲突解决策略;给出权限分配界面交互设计、权限选择器实现原理、权限验证中间件开发思路;并补充权限数据缓存、实时权限更新与变更通知、权限审计日志与使用统计分析等能力。
项目结构
DouPHP 的后台权限体系由“中间件 + 授权判定服务 + 管理员权限配置”三部分构成:
- 中间件:在请求进入控制器前进行鉴权拦截。
- 授权判定:集中封装“当前管理员是否可访问某模块/动作”的策略。
- 管理员权限配置:以 action_list 字段存储已授权的模块集合,配合超级管理员类型进行放行。
graph TB
A["浏览器/客户端"] --> B["路由层<br/>admin/route/*.php"]
B --> C["中间件链<br/>auth → permission → workspace"]
C --> D["控制器/服务"]
C --> E["权限判定服务<br/>AdminGate"]
E --> F["管理员上下文<br/>type / action_list / admin_id"]
核心组件
- 权限中间件:负责从登录上下文取管理员信息、解析当前模块/动作/目标ID,并调用授权判定服务进行放行或拒绝。
- 授权判定服务:定义子资源到父资源的鉴权别名映射,处理超级管理员放行、manager 自编辑放行、defined 类型按 action_list 白名单校验。
- 管理员权限列表生成:根据系统配置与基础菜单,输出可供勾选的模块清单,用于新增/编辑管理员时的权限分配界面。
架构总览
后端请求进入后台后,先经过认证中间件注入管理员上下文,再由权限中间件依据 AdminGate 的策略判断是否允许访问当前模块/动作。对于小程序工作台等跨端场景,通过统一接口进行权限校验,失败则降级回首页。
sequenceDiagram
participant U as "用户"
participant R as "路由/中间件"
participant M as "权限中间件"
participant G as "AdminGate"
participant S as "控制器/服务"
U->>R : 发起后台请求
R->>M : 进入权限中间件
M->>M : 读取管理员上下文/解析模块/动作/目标ID
M->>G : canAccess(管理员, 模块, 动作, 目标ID)
G-->>M : 返回 true/false
alt 允许
M->>S : 继续执行控制器
S-->>U : 返回响应
else 拒绝
M-->>U : 重定向至管理首页
end
详细组件分析
权限中间件(PermissionMiddleware)
- 职责:在认证通过后,检查当前管理员对当前模块/动作的访问权限。
- 关键点:
- 未登录直接重定向到登录页。
- 无模块时重定向到管理首页。
- 将 module/action/id 传入授权判定服务。
- 无权时重定向到管理首页。
flowchart TD
Start(["进入权限中间件"]) --> CheckAuth["检查登录状态"]
CheckAuth --> |未登录| RedirectLogin["重定向到登录页"]
CheckAuth --> |已登录| ParseRoute["解析 routeModule/routeAction/id"]
ParseRoute --> HasModule{"是否存在模块?"}
HasModule --> |否| RedirectHome["重定向到管理首页"]
HasModule --> |是| CallGate["调用 AdminGate.canAccess()"]
CallGate --> Allowed{"是否允许?"}
Allowed --> |否| RedirectHome
Allowed --> |是| Next["放行到下一个中间件/控制器"]
授权判定服务(AdminGate)
- 职责:承载“能否访问指定后台模块/动作”的核心策略。
- 关键规则:
- 超级管理员(type 非 defined)直接放行。
- manager 模块的“编辑/更新自身资料”放行(仅本人)。
- 子资源 module 经别名表归一到父 module 再查 action_list。
- defined 类型管理员按 action_list 白名单判定。
flowchart TD
S(["canAccess(admin,module,action,targetId)"]) --> TypeCheck{"type != 'defined' ?"}
TypeCheck --> |是| AllowSuper["放行超级管理员"]
TypeCheck --> |否| ModuleCheck{"module 是否为空?"}
ModuleCheck --> |是| DenyEmpty["拒绝无模块"]
ModuleCheck --> |否| SelfEdit{"是否 manager 自编辑?"}
SelfEdit --> |是| AllowSelf["放行本人编辑"]
SelfEdit --> |否| AliasMap["子资源→父资源别名映射"]
AliasMap --> ActionList["解析 action_list 并判断包含性"]
ActionList --> Result{"是否在白名单?"}
Result --> |是| Allow["允许"]
Result --> |否| Deny["拒绝"]
管理员权限列表生成(ManagerService.adminActionList)
- 职责:为“新增/编辑管理员”页面提供可选的模块权限清单。
- 数据来源:
- 系统配置的模块集合(含分类模块、单页模块、基础菜单)。
- 当前管理员已有的 action_list 作为选中状态。
- 过滤隐藏模块与纯模式开关。
flowchart TD
A["输入: admin_id"] --> LoadUser["加载用户 action_list"]
LoadUser --> BuildList["遍历配置模块<br/>组装 value/name/cur"]
BuildList --> MergeBasic["合并基础菜单项"]
MergeBasic --> Return["返回权限选项列表"]
小程序工作台权限校验
- 职责:跨模块共用,校验当前用户是否有权进入指定工作台模块;无权则返回首页。
- 行为:
- 若路由不存在(未安装 work 模块),视为无权限并返回首页。
- 若后端校验失败,同样返回首页。
sequenceDiagram
participant P as "小程序页面"
participant S as "权限服务"
participant API as "work.permission 接口"
P->>S : checkWorkPermission(module)
S->>API : POST {module}
alt 成功
API-->>S : 允许
S-->>P : 继续渲染
else 失败/路由不存在
API-->>S : 拒绝或异常
S-->>P : switchTab 返回首页
end
依赖关系分析
- 中间件依赖授权服务:PermissionMiddleware 依赖 AdminGate 完成策略判定。
- 授权服务依赖管理员上下文:AdminGate 依赖 type、action_list、admin_id 等上下文信息。
- 权限分配界面依赖配置:ManagerService 依赖系统配置与基础菜单生成可选项。
- 工具路由豁免鉴权:tool.php 中暴露 routes_js/lang_js 等脚本,豁免 auth/permission/workspace,确保未登录或受限管理员也能获取必要静态资源。
graph LR
PM["PermissionMiddleware"] --> AG["AdminGate"]
AG --> CTX["管理员上下文"]
MS["ManagerService"] --> CFG["系统配置/基础菜单"]
RT["tool.php 路由"] --> EX["豁免中间件"]
性能与缓存
- 建议缓存点:
- 管理员上下文中的 action_list 可在会话/缓存中短期缓存,减少重复解析。
- 权限选项列表(adminActionList)可按管理员ID缓存,降低频繁查询配置的成本。
- 实时更新:
- 当管理员权限变更后,应使相关缓存失效(如按 admin_id 维度清理)。
- 对小程序工作台等跨端场景,建议在权限变更后推送通知或下次请求时强制刷新。
- 变更通知:
- 可通过站内消息或 WebSocket 推送“权限已变更”提示,引导用户重新加载菜单或刷新页面。
故障排查指南
- 现象:登录后仍被重定向到管理首页
- 检查是否已通过认证中间件注入管理员上下文。
- 检查当前模块/动作是否正确解析。
- 检查 AdminGate 的别名映射是否覆盖当前子资源。
- 检查 action_list 是否包含当前模块。
- 现象:manager 自编辑被拒绝
- 确认 action 为 edit/update。
- 确认 targetId 与当前 admin_id 一致。
- 现象:小程序工作台无法进入
- 检查 work 模块是否安装且路由存在。
- 检查 work.permission 接口是否返回允许。
- 现象:静态资源(routes_js/lang_js)被拦截
- 确认 tool.php 对应路由已豁免 auth/permission/workspace。
结论
DouPHP 后台权限体系以“中间件 + 授权服务 + 管理员权限配置”为核心,采用白名单策略与别名继承,既满足细粒度控制,又兼顾扩展性。结合小程序工作台权限校验与工具路由豁免,形成前后端一致的权限控制闭环。建议在生产环境引入缓存与变更通知机制,提升体验与可维护性。
附录:API 与前端控制要点
- 后端接口
- 后台模块访问:由中间件自动拦截,无需业务控制器额外处理。
- 小程序工作台权限:POST work.permission,参数 module;失败则返回首页。
- 前端控制
- 后台菜单:基于 ManagerService.adminActionList 返回的选项渲染复选框,提交后写入 action_list。
- 按钮级控制:在前端模板中根据当前管理员的 action_list 显示/隐藏按钮。
- 小程序工作台:调用 checkWorkPermission(module),失败则 switchTab 返回首页。
- 审计与统计
- 建议记录每次权限判定结果(成功/失败)、操作者、IP、时间,便于审计与统计分析。
- 统计高频访问模块与长期未使用模块,辅助权限回收与优化。