简介
本技术文档聚焦 DouPHP 后台权限管理系统,围绕基于角色的访问控制(RBAC)模型展开,覆盖管理员身份认证、模块级资源访问控制、菜单权限展示、中间件拦截链、动态权限校验、登录安全(限流与锁定)、以及可扩展的权限体系设计。文档面向希望二次开发或集成权限能力的开发者,提供从架构到落地的完整说明与图示。
项目结构
DouPHP 将权限相关能力按职责分层组织:
- 中间件层:负责请求进入时的认证与授权拦截
- 服务层:封装认证、授权判定、菜单数据等核心业务逻辑
- 模型层:管理管理员账户、登录失败计数、锁定时间、记住我令牌等持久化操作
- 基础设施:多 Guard 认证管理器,统一解析 admin/front/api 三端认证上下文
graph TB
subgraph "中间件"
AMW["AuthMiddleware"]
PMW["PermissionMiddleware"]
end
subgraph "服务"
AGATE["AdminGate"]
AMS["AdminMenuService"]
ASVC["AuthService"]
end
subgraph "模型"
MGR["Manager"]
end
subgraph "基础设施"
AUTHM["AuthManager"]
end
AMW --> ASVC
PMW --> AGATE
AGATE --> AMS
ASVC --> MGR
AMW --> AUTHM
核心组件
- 认证中间件(AuthMiddleware):恢复会话中的管理员身份,未登录则重定向至登录页;免登路由通过声明式豁免,不在中间件内硬编码白名单。
- 权限中间件(PermissionMiddleware):在认证通过后,依据当前模块与动作调用 AdminGate 进行模块级访问控制;超级管理员放行,受限管理员按 action_list 白名单判定。
- 授权门(AdminGate):实现 canAccess 判定逻辑,支持子模块别名归一化、自身编辑放行等规则。
- 菜单服务(AdminMenuService):提供框架基础菜单键列表,用于权限映射与权限编辑页面的分组展示。
- 认证服务(AuthService):实现后台管理员的登录、登出、会话恢复、密码校验、记住我、登录失败限流与账号锁定等。
- 管理员模型(Manager):封装 admin 表与 admin_log 表的读写,包括登录失败统计、锁定时间、记住我令牌等。
- 认证管理器(AuthManager):多 Guard 注册与解析,强制显式 guard 名,避免默认 guard 歧义。
架构总览
后台请求进入时,先经认证中间件恢复管理员会话,再经权限中间件进行模块级访问控制。认证服务负责登录态建立与会话恢复,授权门根据管理员上下文与当前路由判定是否允许访问。菜单服务提供静态菜单键集合,配合权限系统渲染可见菜单。
sequenceDiagram
participant C as "客户端"
participant MW1 as "认证中间件"
participant MW2 as "权限中间件"
participant G as "授权门(AdminGate)"
participant S as "认证服务(AuthService)"
participant DB as "数据库"
C->>MW1 : "发起后台请求"
MW1->>S : "restoreFromSession()"
S->>DB : "读取会话/记住我令牌并验证"
DB-->>S : "管理员信息或空"
S-->>MW1 : "返回上下文或null"
alt "未登录"
MW1-->>C : "重定向到登录页"
else "已登录"
MW1->>MW2 : "继续管道"
MW2->>G : "canAccess(admin, module, action, id)"
G-->>MW2 : "true/false"
alt "无权限"
MW2-->>C : "重定向到首页"
else "有权限"
MW2-->>C : "交由控制器处理"
end
end
详细组件分析
认证中间件(AuthMiddleware)
- 职责:仅做认证单一职责,恢复会话后注入管理员上下文;未登录抛异常并重定向到登录页。
- 免登策略:通过路由级 withoutMiddleware 声明式豁免,不在此处维护白名单。
- 视图全局变量由工作区中间件承载,模块准入由权限中间件承载。
flowchart TD
Start(["进入认证中间件"]) --> Restore["恢复会话管理员"]
Restore --> Check{"是否已登录?"}
Check -- "否" --> Redirect["重定向到登录页"]
Check -- "是" --> Next["放行到下一个中间件"]
Redirect --> End(["结束"])
Next --> End
权限中间件(PermissionMiddleware)
- 职责:在认证通过后检查当前模块访问权限;超级管理员直接放行;受限管理员按 action_list 白名单判定。
- 入口参数:当前模块、动作、目标管理员 ID(来自请求)。
- 无权限时重定向到后台首页。
flowchart TD
Start(["进入权限中间件"]) --> GetAdmin["获取当前管理员"]
GetAdmin --> HasAdmin{"是否存在?"}
HasAdmin -- "否" --> ToLogin["重定向到登录页"]
HasAdmin -- "是" --> ReadRoute["读取模块/动作/目标ID"]
ReadRoute --> GateCall["调用授权门 canAccess()"]
GateCall --> Allow{"是否允许?"}
Allow -- "否" --> ToHome["重定向到后台首页"]
Allow -- "是" --> Next["放行到控制器"]
ToLogin --> End(["结束"])
ToHome --> End
Next --> End
授权门(AdminGate)
- 核心方法 canAccess:
- 非受限管理员(type != defined)直接放行。
- 受限管理员需匹配 action_list 白名单;子模块通过别名表归一到父模块。
- manager 模块的“编辑/更新自身资料”单独放行(仅限本人)。
- 子模块别名:如 aigenerate* 归一到 ai,weixin_media_article 归一到 weixin_media。
classDiagram
class AdminGate {
+canAccess(admin, cur, action, targetId) bool
-isManagerSelfEdit(admin, cur, action, targetId) bool
-subModuleAliases : map
}
菜单服务(AdminMenuService)
- 提供框架基础菜单键列表,用于权限映射与权限编辑页面分组。
- 典型键包括设置、导航、页面、备份、小程序、主题、管理员、模块、云、语言等。
认证服务(AuthService)
- 登录流程:
- attempt:校验凭据、IP 限流、账号锁定、密码校验、写入会话与记住我令牌。
- login:会话再生、写入 session、重置登录失败状态、更新最后登录时间与 IP、发放 remember-me。
- logout:清空会话、清除 remember cookie、重置实例状态。
- 会话恢复:
- restoreFromSession:尝试记住我自动登录,校验 admin_id + shell,构建上下文并 hydrate。
- 安全特性:
- IP 限流:基于最近 N 秒失败次数阈值。
- 账号锁定:达到失败阈值后锁定一段时间。
- 密码升级:历史 md5 自动升级为 bcrypt。
- 会话心跳:超时清理会话。
sequenceDiagram
participant U as "管理员"
participant A as "认证服务"
participant M as "管理员模型"
participant S as "会话"
U->>A : "attempt(username,password,ip)"
A->>A : "ipRateLimited(ip)"
A->>M : "findByUsername(username)"
M-->>A : "用户行"
A->>A : "isLocked(id)"
A->>A : "verifyPassword(password,user)"
alt "成功"
A->>A : "login(user,remember,ip)"
A->>S : "写入session/ontime/shell"
A->>M : "updateLastLogin/updateRememberToken"
A-->>U : "true"
else "失败"
A->>M : "recordLoginFail(id)"
A-->>U : "false"
end
管理员模型(Manager)
- 字段与可写范围:包含用户名、邮箱、密码、action_list、创建时间等。
- 登录安全:
- updateLoginFailState:记录失败次数与锁定时间。
- getLoginLockTime:读取锁定时间。
- countLoginFailuresByIp:按 IP 统计近期失败次数。
- 记住我与密码重置:
- updateRememberToken:写入记住我令牌与过期时间。
- updatePasswordResetToken / completePasswordReset:密码重置流程。
认证管理器(AuthManager)
- 多 Guard 注册与解析:强制显式 guard 名(admin/front/api),避免默认 guard 歧义。
- 工厂模式:各端 Init 阶段注册自身 guard 工厂;首次解析后缓存实例。
- 测试支持:forget 方法可清空指定或全部 guard 缓存。
依赖关系分析
- 中间件依赖服务:
- AuthMiddleware 依赖 AuthService 进行会话恢复。
- PermissionMiddleware 依赖 AdminGate 进行模块级授权判定。
- 服务依赖模型:
- AuthService 依赖 Manager 进行管理员数据与日志查询。
- 授权门依赖菜单服务:
- AdminGate 使用 AdminMenuService 的基础菜单键集合进行权限映射与展示。
graph LR
AMW["AuthMiddleware"] --> ASVC["AuthService"]
PMW["PermissionMiddleware"] --> AGATE["AdminGate"]
AGATE --> AMS["AdminMenuService"]
ASVC --> MGR["Manager"]
性能与缓存策略
- 会话与会话心跳:
- 登录成功后生成新会话 ID,写入 ontime 心跳;超时会话清理,减少无效会话占用。
- 记住我令牌:
- 使用哈希令牌与过期时间,降低频繁校验成本;续登成功后补发 CSRF 静态令牌,避免后续表单校验失败导致假性登出。
- 登录失败限流与锁定:
- 基于 admin_log 统计近期失败次数,命中阈值后锁定账号,减轻暴力破解压力。
- 菜单与权限映射:
- 基础菜单键为静态配置,减少运行时计算开销;子模块别名集中管理,避免重复判断。
- 建议优化:
- 对高频访问的菜单与权限映射可引入内存缓存(如 Redis),并在权限变更时主动失效。
- 对 IP 限流与锁定时间可结合分布式锁或外部缓存,提升并发场景下的准确性。
故障排查指南
- 无法进入后台:
- 检查认证中间件是否正确恢复会话;确认路由是否声明了免登豁免。
- 查看权限中间件是否因无权限被重定向到首页。
- 频繁被踢出:
- 检查会话心跳是否超时;确认 remember-me 令牌是否有效且未过期。
- 核对 CSRF 静态令牌是否在续登后被正确补发。
- 登录失败提示:
- 查看 IP 限流是否命中;检查账号是否处于锁定状态。
- 核对密码是否为历史 md5,必要时触发自动升级。
- 权限误判:
- 确认管理员 type 是否为受限类型;检查 action_list 是否包含当前模块。
- 子模块是否已在别名表中登记;manager 自编辑是否满足本人条件。
结论
DouPHP 后台权限系统以中间件为核心拦截点,结合认证服务与授权门实现细粒度的模块级访问控制。通过会话心跳、记住我令牌、IP 限流与账号锁定等机制保障登录安全;菜单服务提供静态菜单键集合,便于权限映射与展示。整体架构清晰、职责分离明确,具备良好的可扩展性与可维护性。
附录:扩展与最佳实践
- 自定义角色与权限组:
- 在管理员模型中扩展 role/group 字段,并在 AdminGate 中增加角色判定逻辑。
- 将新增角色对应的模块与动作加入 action_list 或新的权限矩阵。
- 细粒度权限控制:
- 在 AdminGate 中扩展 canAccess 方法,支持按资源 ID 或数据归属进行判定。
- 结合业务模型增加数据级权限(如仅能编辑本部门数据)。
- 权限审计日志:
- 在关键权限判定结果处记录审计日志(成功/拒绝),便于事后追溯。
- 利用现有 admin_log 能力扩展审计维度(模块、动作、目标 ID、结果)。
- 缓存策略:
- 对菜单与权限映射引入缓存,并在权限变更时主动失效。
- 对 IP 限流与锁定时间使用外部缓存,提升高并发场景稳定性。
- 扩展指南:
- 新增子模块需在 AdminGate 的别名表中登记,确保权限透明继承父模块。
- 新增菜单键需在 AdminMenuService 中维护,保证权限编辑页面显示一致。