简介
本文件面向 DouPHP 的权限控制系统,围绕“角色管理、资源权限、中间件拦截、API 授权、动态配置与实时更新、审计与违规检测”等主题进行系统化说明。文档基于仓库中已实现的后台管理员鉴权、API 端会员鉴权与策略配置、以及管理端菜单与动作白名单机制,给出可操作的架构解读与落地建议。
项目结构
DouPHP 将权限控制拆分为“认证(登录态)+ 授权(访问判定)+ 中间件(拦截)+ 配置(策略)+ 审计(记录)”五个层次:
- 认证层:Admin AuthService(后台)、API UserAuthMiddleware(前端 API),统一通过 AuthManager 解析 guard。
- 授权层:AdminGate(后台模块/动作白名单)、API 鉴权模式配置(module/sub/action 级 required/optional/public)。
- 中间件层:Admin AuthMiddleware/PermissionMiddleware、API UserAuthMiddleware。
- 配置层:admin 侧 action_list 白名单;api/init/middleware.php 中的 auth_modes 与 work_required。
- 审计层:各业务 Service 调用 audit()->writeAdminLog(...) 记录操作日志,供后续审计与违规检测使用。
graph TB
subgraph "后台"
A["AuthMiddleware<br/>恢复会话"] --> B["PermissionMiddleware<br/>模块/动作白名单"]
B --> C["控制器/服务"]
end
subgraph "API"
D["UserAuthMiddleware<br/>按策略校验"] --> E["控制器/服务"]
end
F["AuthManager<br/>多Guard注册"] --> A
F --> D
G["AdminGate<br/>白名单判定"] --> B
H["auth_modes / work_required<br/>API策略配置"] --> D
核心组件
- 后台认证 Guard:AuthService 实现 StatefulGuardContract,负责会话恢复、登录写入、remember-me、密码升级与失败锁定。
- 后台授权 Gate:AdminGate 承载「当前管理员能否访问某模块/动作」的判定逻辑,支持子资源别名继承父模块权限。
- 后台中间件:AuthMiddleware 负责恢复登录态;PermissionMiddleware 在登录后检查模块/动作白名单。
- API 鉴权:UserAuthMiddleware 读取 Authorization 头并交由抽象基类与策略配置完成 required/optional/public 分支处理。
- 多 Guard 管理器:AuthManager 提供 extend/guard/forget,强制显式 guard 名,避免默认 guard 歧义。
- 管理员权限列表:ManagerService.adminActionList 生成后台勾选菜单,结合 Config 过滤展示项。
架构总览
下图展示了请求进入后端后的认证与授权路径,覆盖后台与 API 两条主线。
sequenceDiagram
participant Client as "客户端"
participant AdminMW as "Admin AuthMiddleware"
participant PermMW as "Admin PermissionMiddleware"
participant Gate as "AdminGate"
participant API as "API UserAuthMiddleware"
participant Policy as "UserAuthPolicy"
participant Controller as "控制器/服务"
Note over Client,AdminMW : 后台请求
Client->>AdminMW : 进入后台路由
AdminMW->>AdminMW : restoreFromSession()
AdminMW-->>Client : 未登录跳转登录页
AdminMW-->>PermMW : 已登录放行
PermMW->>Gate : canAccess(admin, module, action, id)
alt 无权限
Gate-->>PermMW : false
PermMW-->>Client : 重定向到后台首页
else 有权限
Gate-->>PermMW : true
PermMW-->>Controller : 继续执行
end
Note over Client,API : API 请求
Client->>API : 携带 Authorization : Bearer token
API->>Policy : 根据 auth_modes 匹配 module/sub/action
alt public/optional/required
Policy-->>API : 允许或拒绝
API-->>Client : JSON 错误响应或继续
end
详细组件分析
后台管理员角色与权限分组
- 角色类型:管理员行包含 type 字段,当 type 非 defined 时视为超级管理员,直接放行;defined 类型需按 action_list 白名单判定。
- 权限分组:action_list 为逗号分隔的模块名集合,用于控制后台模块访问;ManagerService.adminActionList 从配置与基础菜单构建可选模块清单,供新增/编辑管理员时勾选。
- 子资源继承:AdminGate 维护子资源到父资源的别名映射,使子资源透明继承父模块权限,避免新增子资源后出现误拦截。
flowchart TD
Start(["进入 canAccess"]) --> CheckType{"type != 'defined' ?"}
CheckType --> |是| Allow["放行超级管理员"]
CheckType --> |否| CheckCur{"cur 是否为空?"}
CheckCur --> |是| Deny["拒绝"]
CheckCur --> |否| SelfEdit{"是否 manager 自编辑?"}
SelfEdit --> |是| Allow
SelfEdit --> |否| Alias{"是否存在子资源别名?"}
Alias --> |是| Map["归一到父模块"]
Alias --> |否| Next["保持 cur"]
Map --> CheckList["cur 是否在 action_list?"]
Next --> CheckList
CheckList --> |是| Allow
CheckList --> |否| Deny
资源权限控制机制(菜单、操作、数据)
- 菜单权限:由 ManagerService 基于配置与基础菜单生成可选模块清单,管理员勾选后持久化为 action_list。
- 操作权限:PermissionMiddleware 在每次请求时依据 module/action 与 admin 上下文判定;AdminGate 支持子资源别名继承。
- 数据权限:当前代码未实现细粒度数据权限(如按属主/部门过滤),建议在 Service 层按业务模型增加属主/租户/部门条件,并在查询前注入。
PermissionMiddleware 实现原理与拦截流程
- 前置依赖:AuthMiddleware 已完成会话恢复,确保 auth('admin')->user() 可用。
- 拦截点:PermissionMiddleware 提取当前 module/action/targetId,调用 AdminGate.canAccess 判定;未通过则重定向回后台首页。
- 异常处理:未登录或无模块时抛出 HttpResponseException 并跳转;无权限时同样跳转。
sequenceDiagram
participant MW as "PermissionMiddleware"
participant Auth as "auth('admin')"
participant Req as "Request"
participant Gate as "AdminGate"
participant Ctrl as "控制器"
MW->>Auth : user()
Auth-->>MW : admin 上下文
MW->>Req : routeModule()/routeAction()/id
MW->>Gate : canAccess(admin, module, action, id)
alt 无权限
Gate-->>MW : false
MW-->>Ctrl : 抛出异常并重定向
else 有权限
Gate-->>MW : true
MW-->>Ctrl : next()
end
API 级别的权限控制(接口访问与方法级验证)
- 策略配置:api/init/middleware.php 定义 auth_modes(public/optional/required)与 work_required(工作端身份叠加)。
- 中间件:UserAuthMiddleware 从 Authorization 头提取 token,交由抽象基类与策略配置决定放行或返回 401/403。
- 方法级校验:部分控制器内部再调用工作端权限检查(如 WorkController.permission),以细化到具体模块/子段。
sequenceDiagram
participant Client as "客户端"
participant API as "UserAuthMiddleware"
participant Policy as "UserAuthPolicy"
participant Ctrl as "控制器"
Client->>API : GET /api/{module}/{sub}/{action}
API->>Policy : 匹配 module/sub/action -> 模式
alt public
Policy-->>API : 不解析登录态
API-->>Ctrl : 放行
else optional
Policy-->>API : 尝试解析登录态
API-->>Ctrl : 无论成功与否均放行
else required
Policy-->>API : 必须登录
alt 无登录态
API-->>Client : 401 JSON
else 有登录态
API-->>Ctrl : 放行
end
end
动态权限配置与实时权限更新
- 后台管理员权限:action_list 存储在管理员表中,修改后立即生效于下一次请求的 PermissionMiddleware 判定。
- API 鉴权策略:auth_modes 与 work_required 位于配置文件,修改后需重启应用或重新加载配置方可生效。
- 建议增强:
- 引入缓存键(如 admin:{id}:perms)并在管理员权限变更时失效,减少数据库读取。
- 对 API 策略配置提供热重载能力(如监听文件变更或配置中心推送),避免重启影响。
权限审计与违规检测方案
- 现有实践:多处 Service 在增删改操作后调用 audit()->writeAdminLog(...) 记录操作模块、动作与结果。
- 违规检测建议:
- 基于审计日志聚合统计高频失败、越权尝试、敏感操作(删除/导出)等指标。
- 结合 IP、时间窗、操作频率建立规则引擎,触发告警或临时封禁。
- 将审计日志纳入集中式日志系统,支持检索与可视化看板。
依赖关系分析
- 中间件依赖:
- PermissionMiddleware 依赖 AdminGate 与 auth('admin')。
- AuthMiddleware 依赖 auth('admin')->restoreFromSession()。
- API UserAuthMiddleware 依赖抽象基类与策略配置。
- 配置依赖:
- ManagerService 依赖 Config 的 module 相关配置生成权限选项。
- API 鉴权依赖 api/init/middleware.php 的策略表。
- 外部集成:
- AuthService 依赖 Session、DB、Manager 模型进行登录态与凭据校验。
graph LR
AuthMW["AuthMiddleware"] --> AM["AuthManager"]
PermMW["PermissionMiddleware"] --> AG["AdminGate"]
API["UserAuthMiddleware"] --> POL["UserAuthPolicy"]
AG --> CFG["Config(模块/菜单)"]
API --> MODE["auth_modes/work_required"]
AM --> Sess["Session/DB"]
性能考虑
- 后台权限判定:AdminGate.canAccess 仅做字符串比较与数组查找,复杂度低;若 action_list 过长,建议缓存并按用户维度隔离。
- API 鉴权:策略匹配为键值查找,命中优先顺序为 module/sub/action → module/sub → module → 默认;建议保持策略表精简。
- 会话与会话心跳:AuthService.touchSession 定期刷新会话有效期,避免长时间空闲导致意外登出。
- 建议:
- 对 AdminGate 判定结果按 admin_id + module/action 做短期缓存。
- 对 API 策略配置变更采用热更新,避免重启。
故障排查指南
- 后台无法访问模块:
- 检查管理员 type 是否为 defined,若是则确认 action_list 是否包含目标模块。
- 若为子资源,确认子资源别名是否正确登记至 AdminGate::$subModuleAliases。
- API 返回 401/403:
- 确认对应 module/sub/action 是否在 auth_modes 中正确声明。
- 对于 work_required 模块,确认工作端身份校验是否通过。
- 会话频繁失效:
- 检查 remember-me 是否启用且 Cookie 有效;确认 touchSession 是否被调用。
- 核对超时阈值与服务器 GC 策略。
结论
DouPHP 的权限体系以“中间件拦截 + 策略配置 + 白名单判定”为核心,后台通过 AdminGate 与 action_list 实现模块级访问控制,API 通过 auth_modes 与工作端策略实现细粒度授权。当前已具备完善的审计记录能力,可在现有基础上扩展数据权限与动态热更,进一步提升灵活性与可观测性。
附录
- 关键术语
- 超级管理员:type 非 defined 的管理员,拥有全量权限。
- 定义型管理员:type 为 defined,需按 action_list 白名单访问。
- 子资源别名:子模块透明继承父模块权限的映射表。
- 鉴权模式:API 端的 public/optional/required 三种访问级别。
- 工作端策略:work_required 要求额外的工作身份校验。