简介
本文件面向 DouPHP 后台的 RBAC(基于角色的访问控制)权限体系,围绕“用户—角色—权限”的关系设计,说明管理员登录态、模块级权限判定、菜单展示、审计日志等关键流程的实现原理与扩展方式。文档同时给出添加新角色类型、配置权限规则、动态菜单显示、权限数据查询优化与缓存策略、以及安全建议等实操指导。
项目结构
DouPHP 后台权限相关代码主要分布在以下位置:
- 认证与会话:admin/service/auth/AuthService.php
- 权限判定:admin/service/authorization/AdminGate.php
- 中间件:admin/middleware/PermissionMiddleware.php
- 多 Guard 管理器:core/foundation/auth/AuthManager.php
- 菜单元数据:admin/service/menu/AdminMenuService.php
- 审计日志:core/service/audit/AuditService.php
- 数据库表结构:_'doc/开发手册/系统表结构.sql
graph TB
A["请求进入<br/>admin 路由"] --> B["AuthMiddleware<br/>注入登录态"]
B --> C["PermissionMiddleware<br/>调用 AdminGate 判定"]
C --> D{"是否允许?"}
D --> |否| E["重定向到登录页或首页"]
D --> |是| F["控制器处理业务"]
F --> G["AuditService 记录操作日志"]
核心组件
- 认证守卫(AdminGuard):负责管理员身份解析、登录/登出、会话恢复、密码校验、失败锁定与续登凭证发放。
- 授权门(AdminGate):根据管理员上下文中的 type 与 action_list,判定当前模块是否可访问;支持子资源别名归一化与自编辑放行。
- 权限中间件(PermissionMiddleware):在路由层统一拦截,调用 AdminGate 进行模块级鉴权。
- 多 Guard 管理器(AuthManager):集中注册并解析 admin/front/api 三个端口的 Guard,提供单例缓存。
- 菜单服务(AdminMenuService):提供框架基础菜单键列表,用于权限映射与权限编辑页展示。
- 审计服务(AuditService):统一写入后台操作日志,便于追踪与审计。
架构总览
RBAC 在 DouPHP 后台以“模块级白名单 + 超级管理员直通”的方式实现:
- 管理员表包含 action_list 字段,存储该管理员可访问的模块集合(逗号分隔)。
- 超级管理员(type 非 defined)直接放行。
- 普通管理员(type 为 defined)需命中 action_list 才能访问对应模块。
- 部分子资源通过别名映射到父模块,简化权限配置。
- 中间件在每次请求时执行判定,未通过则重定向。
sequenceDiagram
participant U as "浏览器"
participant MW as "PermissionMiddleware"
participant G as "AdminGate"
participant DB as "数据库"
participant AUD as "AuditService"
U->>MW : 访问后台模块
MW->>G : canAccess(admin, module, action, targetId)
G-->>MW : 允许/拒绝
alt 拒绝
MW-->>U : 重定向到登录/首页
else 允许
MW->>AUD : 可选记录访问审计
MW-->>U : 继续控制器处理
end
详细组件分析
认证守卫 AuthService
职责边界:
- 身份解析:id()/user()/check()/guest()
- 登录写入:attempt()/login()/logout()
- 会话恢复:restoreFromSession()
- 登录前置检测:ipRateLimited()/isLocked()/lockSecondsRemaining()
关键点:
- attempt() 完成凭据校验、IP 限流、账号锁定检查、密码校验、写入 Session 与记住我令牌。
- login() 生成会话、更新最后登录信息、必要时发放 remember-me 令牌。
- restoreFromSession() 从 Session/Cookie 恢复管理员上下文,并在需要时补发 CSRF 静态令牌。
- verifyPassword() 兼容历史 md5 并自动升级为 bcrypt。
- recordLoginFail() 累计失败次数,达到阈值后锁定一段时间。
flowchart TD
Start(["attempt() 入口"]) --> CheckCred["校验用户名/密码"]
CheckCred --> IPCheck{"IP 限流命中?"}
IPCheck --> |是| Fail["返回失败"]
IPCheck --> |否| FindUser["按用户名查找管理员"]
FindUser --> UserFound{"找到用户?"}
UserFound --> |否| Fail
UserFound --> LockCheck{"账号锁定?"}
LockCheck --> |是| Fail
LockCheck --> VerifyPwd["校验密码"]
VerifyPwd --> PwdOk{"密码正确?"}
PwdOk --> |否| RecordFail["记录失败次数/可能锁定"] --> Fail
PwdOk --> |是| Login["写入会话/更新登录信息/可选续登令牌"]
Login --> Success["返回成功"]
授权门 AdminGate
功能要点:
- canAccess() 对 type 非 defined 的管理员直接放行;defined 类型依据 action_list 白名单判定。
- 子资源通过 $subModuleAliases 映射到父模块,避免重复配置。
- manager 模块的自身资料编辑/更新单独放行(仅本人)。
flowchart TD
S(["canAccess()"]) --> TypeCheck{"type != defined ?"}
TypeCheck --> |是| Allow["允许"]
TypeCheck --> |否| ModuleCheck{"module 存在?"}
ModuleCheck --> |否| Deny["拒绝"]
ModuleCheck --> SelfEdit{"manager 自身编辑?"}
SelfEdit --> |是| Allow
SelfEdit --> |否| Alias["子资源别名归一化"]
Alias --> Match{"action_list 包含 module?"}
Match --> |是| Allow
Match --> |否| Deny
权限中间件 PermissionMiddleware
作用:
- 确保已登录且具备模块访问权限,否则重定向。
- 从 Request 中获取当前模块、动作与目标 ID,交由 AdminGate 判定。
sequenceDiagram
participant R as "Request"
participant M as "PermissionMiddleware"
participant G as "AdminGate"
R->>M : 进入中间件
M->>M : 读取 routeModule/routeAction/id
M->>G : canAccess(admin, module, action, id)
G-->>M : true/false
alt false
M-->>R : 重定向到登录/首页
else true
M-->>R : 继续后续处理器
end
多 Guard 管理器 AuthManager
职责:
- 集中注册并解析 admin/front/api 三端的 Guard。
- 强制显式指定 guard 名,避免默认 guard 歧义。
- 首次解析后缓存实例,提升性能。
菜单服务 AdminMenuService
职责:
- 提供框架基础菜单键列表,供权限映射与权限编辑页使用。
- 新增模块需在 action_list 中登记相应键,以便权限分配。
审计服务 AuditService
职责:
- 统一写入后台操作日志,包含管理员 ID、动作、模块、IP、结果与详情。
- 可在业务变更点调用,形成完整的权限变更与操作轨迹。
依赖关系分析
- PermissionMiddleware 依赖 AdminGate 进行权限判定。
- AdminGate 依赖管理员上下文(由 AuthService 注入),并通过 action_list 字符串匹配模块。
- AuthService 依赖数据库表 admin 进行身份验证与会话恢复。
- AuditService 依赖 admin_log 表记录操作日志。
- AuthManager 作为多 Guard 的统一入口,解耦各端认证实现。
graph LR
PMW["PermissionMiddleware"] --> AG["AdminGate"]
AG --> AS["AuthService"]
AS --> DB["admin 表"]
PMW --> AUD["AuditService"]
AUD --> LOG["admin_log 表"]
AM["AuthManager"] --> AS
性能与缓存
- 会话与 Cookie:
- 登录成功后写入 Session(admin_id/shell/ontime),并设置 remember-me Cookie(有效期 30 天)。
- 会话心跳刷新,超时清理。
- 数据库访问:
- 身份恢复与密码校验涉及 admin 表查询;建议在高频路径考虑应用级缓存(如内存缓存)以减少重复查询。
- 权限判定:
- AdminGate 的 action_list 为字符串拆分匹配,适合中小规模模块数;若模块数量增长,可考虑将 action_list 持久化为索引表以提升查询效率。
- 审计日志:
- admin_log 写入为追加型,建议定期归档与索引优化(如按时间范围分区)。
故障排查指南
常见问题与定位方法:
- 登录后仍被重定向:
- 检查 PermissionMiddleware 是否正确注入登录态,确认 auth('admin')->user() 非空。
- 核对 AdminGate 的 canAccess() 判定逻辑,确认 action_list 包含当前模块。
- 子资源无法访问:
- 检查 $subModuleAliases 是否已将子资源映射到父模块。
- 记住我失效:
- 检查 remember-me Cookie 是否存在且未过期,确认 tryRememberLogin() 流程正常。
- 审计日志缺失:
- 确认业务变更点调用了 audit()->writeAdminLog(),并检查 admin_log 表写入。
结论
DouPHP 后台采用简洁高效的 RBAC 模型:以管理员 action_list 白名单为核心,结合超级管理员直通与子资源别名映射,满足大多数后台权限需求。通过中间件统一拦截、认证守卫保障登录态、审计服务记录操作轨迹,形成了完整的安全闭环。对于大规模模块场景,可进一步引入权限索引表与应用级缓存以提升性能。
附录:开发示例与最佳实践
添加新的角色类型
- 在管理员表中,type 字段区分超级管理员与普通管理员;如需新增角色类型,可在 AuthService::buildAdminPayload() 中扩展 type 计算逻辑,并在 AdminGate::canAccess() 中增加对应放行或限制规则。
- 参考路径:
- admin/service/auth/AuthService.php:315-329
- admin/service/authorization/AdminGate.php:69-91
配置权限规则
- 为新模块分配权限:
- 在 AdminMenuService::basicMenu() 中添加模块键。
- 在管理员 action_list 字段中写入该模块键(逗号分隔)。
- 若为子资源,需在 AdminGate::$subModuleAliases 中登记映射。
- 参考路径:
- admin/service/menu/AdminMenuService.php:38-53
- admin/service/authorization/AdminGate.php:40-51
实现动态菜单显示
- 前端渲染菜单时,依据当前管理员的 action_list 过滤可用菜单项;可使用 AdminMenuService::basicMenu() 提供的键列表作为基础菜单源。
- 参考路径:
- admin/service/menu/AdminMenuService.php:38-53
权限数据的存储结构与查询优化
- 存储结构:
- admin 表包含 action_list(文本字段,逗号分隔模块键)。
- admin_log 表记录操作日志。
- 查询优化建议:
- 对高频查询的 action_list 可缓存至内存(如应用级缓存),减少重复解析。
- 当模块数量较大时,可将 action_list 拆分为独立关联表,建立索引以提升匹配效率。
- 参考路径:
- _'doc/开发手册/系统表结构.sql:29-58
权限审计日志记录与变更追踪
- 在关键业务变更点调用审计服务,记录管理员 ID、动作、模块、IP、结果与详情。
- 参考路径:
- core/service/audit/AuditService.php:153-178
安全建议
- 密码安全:
- 使用 bcrypt 存储密码,历史 md5 自动升级。
- 参考路径:admin/service/auth/AuthService.php:412-425
- 登录防护:
- 启用 IP 限流与账号锁定机制,防止暴力破解。
- 参考路径:admin/service/auth/AuthService.php:275-303
- admin/service/auth/AuthService.php:433-444
- 会话安全:
- 使用 Session 与 remember-me Cookie,注意超时与重置。
- 参考路径:admin/service/auth/AuthService.php:165-181
- admin/service/auth/AuthService.php:376-403
- 最小权限原则:
- 默认拒绝,按需授予;子资源通过别名映射简化配置但需同步维护。
- 参考路径:admin/service/authorization/AdminGate.php:40-51