文档目录
权限管理系统

简介

本技术文档聚焦 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 中维护,保证权限编辑页面显示一致。
添加日期:2026-10-05