简介
本技术文档聚焦 DouPHP 后台的身份验证与权限控制中间件,围绕 AuthMiddleware(认证)与 PermissionMiddleware(权限)展开,解释请求拦截机制、会话恢复流程、令牌检查逻辑、登录态检测、权限判定规则、动态权限分配等关键实现。同时给出执行顺序、错误处理策略、性能优化建议,以及常见问题与解决方案,帮助开发者安全地扩展中间件能力并实现细粒度权限控制。
项目结构
后台入口通过路由调度器将请求交由中间件管道处理,认证与权限作为前置中间件在控制器之前执行;工作台变量注入中间件位于认证与权限之后,确保仅在已认证的上下文中注入视图变量。
graph TB
A["请求进入<br/>admin/index.php"] --> B["路由解析<br/>AdminResolver"]
B --> C["调度执行<br/>Dispatcher.run()"]
C --> D["中间件管道"]
D --> E["认证中间件<br/>AuthMiddleware"]
E --> F["权限中间件<br/>PermissionMiddleware"]
F --> G["工作台变量注入<br/>AdminWorkspaceMiddleware"]
G --> H["控制器动作"]
核心组件
- 认证中间件(AuthMiddleware)
- 职责:从会话恢复管理员登录态;未登录则重定向到登录页。
- 关键点:使用 auth('admin')->restoreFromSession(ip) 进行会话恢复;失败时抛出响应异常以短路返回。
- 权限中间件(PermissionMiddleware)
- 职责:校验当前管理员对目标模块/动作的访问权限;超级管理员直接放行;普通管理员按白名单判定。
- 关键点:读取 routeModule/routeAction/id,调用 AdminGate::canAccess 进行授权判定。
- 工作台变量注入中间件(AdminWorkspaceMiddleware)
- 职责:为模板注入全局管理员信息、工作区数据与更新角标;仅在认证通过后注入。
- 路由调度器(Router)
- 职责:解析路由计划并交由 Dispatcher 在中间件管道中执行;未匹配或方法不允许时重定向首页并提示。
- 中间件接口(MiddlewareInterface)
- 职责:定义 handle($next) 契约;要求中间件必须 return $next() 以冒泡下层响应。
架构总览
后台请求的生命周期如下:
- 路由层解析出 DispatchPlan,交由中央调度器运行中间件管道。
- 认证中间件优先执行,负责会话恢复与登录态校验。
- 权限中间件随后执行,依据角色与白名单进行模块级访问控制。
- 工作台中间件最后注入视图所需上下文。
- 最终进入控制器业务逻辑。
sequenceDiagram
participant Client as "客户端"
participant Router as "路由调度器"
participant Pipe as "中间件管道"
participant Auth as "认证中间件"
participant Perm as "权限中间件"
participant Work as "工作台中间件"
participant Ctrl as "控制器"
Client->>Router : 发起后台请求
Router->>Pipe : 构建并运行管道
Pipe->>Auth : handle(next)
Auth-->>Pipe : 未登录 -> 重定向登录页
Auth-->>Pipe : 已登录 -> 继续 next()
Pipe->>Perm : handle(next)
Perm-->>Pipe : 无权限 -> 重定向首页
Perm-->>Pipe : 有权限 -> 继续 next()
Pipe->>Work : handle(next)
Work-->>Pipe : 注入 global_admin/workspace/unum
Pipe->>Ctrl : 执行业务逻辑
Ctrl-->>Client : 返回响应
详细组件分析
认证中间件(AuthMiddleware)
- 请求拦截机制
- 从会话恢复管理员登录态,携带客户端 IP 用于会话绑定校验。
- 若恢复失败,立即抛出响应异常并重定向到登录路由。
- 会话验证流程
- 通过门面 auth('admin') 获取守卫实例,调用 restoreFromSession(ip)。
- 成功时将管理员信息写入当前请求上下文,供后续中间件与控制器使用。
- 令牌检查逻辑
- 本中间件不直接校验 CSRF 令牌;CSRF 由独立中间件处理。
- 错误处理
- 未登录统一重定向到登录页,避免泄露内部状态。
- 性能特性
- 仅一次会话读取与判断,开销极低。
flowchart TD
Start(["进入认证中间件"]) --> Restore["从会话恢复管理员登录态<br/>auth('admin')->restoreFromSession(ip)"]
Restore --> Check{"是否恢复成功?"}
Check -- "否" --> Redirect["抛出响应异常并重定向到登录页"]
Check -- "是" --> Next["调用下一个中间件"]
Redirect --> End(["结束"])
Next --> End
权限中间件(PermissionMiddleware)
- 权限验证规则
- 读取当前管理员信息(需认证中间件已注入)。
- 若为空,重定向登录页。
- 读取当前模块与动作(默认 index),以及资源 id。
- 调用 AdminGate::canAccess(admin, module, action, targetId) 判定。
- 超级管理员(type 非 defined)直接放行;普通管理员按 action_list 白名单判定。
- 动态权限分配
- 通过 AdminGate 对外暴露 canAccess 接口,支持基于角色、模块、动作与资源 ID 的动态判定。
- 错误处理
- 无权限时重定向到后台首页,避免越权访问。
- 执行顺序
- 必须在认证中间件之后执行,确保 auth('admin')->user() 可用。
flowchart TD
Start(["进入权限中间件"]) --> GetAdmin["获取当前管理员信息"]
GetAdmin --> AdminCheck{"管理员存在?"}
AdminCheck -- "否" --> ToLogin["重定向到登录页"]
AdminCheck -- "是" --> ReadRoute["读取模块/动作/资源ID"]
ReadRoute --> GateCall["调用 AdminGate::canAccess(...)"]
GateCall --> Can{"是否允许访问?"}
Can -- "否" --> ToHome["重定向到后台首页"]
Can -- "是" --> Next["调用下一个中间件"]
ToLogin --> End(["结束"])
ToHome --> End
Next --> End
工作台变量注入中间件(AdminWorkspaceMiddleware)
- 作用
- 向模板注入 global_admin、workspace、unum 等视图变量。
- 执行时机
- 位于认证与权限之后,确保只有已认证且具备模块访问权的请求才会注入。
- 健壮性
- 若管理员上下文为空或视图引擎不可用,静默跳过,不影响后续处理。
flowchart TD
Start(["进入工作台中间件"]) --> HasAdmin{"是否存在管理员上下文?"}
HasAdmin -- "否" --> Next["直接放行"]
HasAdmin -- "是" --> Engine{"视图引擎可用?"}
Engine -- "否" --> Next
Engine -- "是" --> Inject["注入 global_admin / workspace / unum"]
Inject --> Next
Next --> End(["结束"])
路由调度器(Router)
- 职责
- 解析路由计划,处理“方法不允许”和“未找到”的情况,统一重定向至后台首页并附带提示信息。
- 将计划交给 Dispatcher 在中间件管道中执行。
- 与中间件的关系
- 中间件在管道内执行,Router 负责整体编排与异常路径的重定向。
sequenceDiagram
participant R as "Router"
participant Res as "AdminResolver"
participant D as "Dispatcher"
R->>Res : resolve(request, container)
alt 方法不允许
R-->>R : 重定向首页并带错误提示
else 未找到
R-->>R : 重定向首页并带错误提示
else 正常
R->>D : run(plan, container)
D-->>R : 返回 Response 或 null
end
初始化与守卫注册(Init)
- 启动流程
- 设置常量、加载核心对象、注册 admin 认证守卫、装配视图引擎与模块。
- 与认证的关系
- 通过 AuthService 注册 auth('admin') 守卫,供中间件使用。
- 其他
- 计算 ROOT_URL 等站点常量,便于重定向与模板渲染。
依赖关系分析
- 中间件之间耦合度低,遵循单一职责原则:
- AuthMiddleware 只负责认证与会话恢复。
- PermissionMiddleware 只负责权限判定。
- AdminWorkspaceMiddleware 只负责视图变量注入。
- 外部依赖
- auth('admin') 守卫由 Init 注册。
- AdminGate 提供权限判定能力。
- Request 提供路由参数与元信息。
- 响应异常 HttpResponseException 用于短路返回。
classDiagram
class MiddlewareInterface {
+handle(next) mixed
}
class AuthMiddleware {
+handle(next) mixed
}
class PermissionMiddleware {
-gate : AdminGate
+handle(next) mixed
}
class AdminWorkspaceMiddleware {
-workspaceBuilder : WorkspaceBuilder
-badgeBuilder : UpdateBadgeBuilder
+handle(next) mixed
}
class Router {
+dispatch() Response|null
}
AuthMiddleware ..|> MiddlewareInterface
PermissionMiddleware ..|> MiddlewareInterface
AdminWorkspaceMiddleware ..|> MiddlewareInterface
Router --> AuthMiddleware : "管道中使用"
Router --> PermissionMiddleware : "管道中使用"
Router --> AdminWorkspaceMiddleware : "管道中使用"
性能考虑
- 最小化 I/O
- 认证中间件仅进行一次会话读取与判断,避免重复查询。
- 早短路
- 未登录或未授权立即重定向,减少后续中间件与控制器开销。
- 视图注入条件化
- 工作台中间件在管理员上下文缺失或视图引擎不可用时跳过注入,降低无效计算。
- 路由层统一处理
- 路由层对“方法不允许/未找到”统一重定向,避免多次分支判断。
故障排查指南
- 无法登录或频繁跳转登录页
- 检查会话是否正确保存与恢复;确认 restoreFromSession 传入的 IP 与请求一致。
- 查看认证中间件是否在管道最前执行。
- 登录后仍提示无权限
- 确认权限中间件在认证之后执行;检查 AdminGate::canAccess 的判定逻辑与白名单配置。
- 模板变量缺失
- 检查工作台中间件是否被跳过(管理员上下文为空或视图引擎不可用)。
- 路由 404 或方法不允许
- 查看路由解析结果;确认请求方法与路由定义一致。
结论
DouPHP 后台通过清晰的中间件分层实现了安全的认证与权限控制:认证中间件保障登录态,权限中间件实施模块级访问控制,工作台中间件按需注入视图上下文。配合路由层的统一处理与接口契约约束,系统具备良好的可维护性与扩展性。开发者可在不破坏现有链路的前提下,通过扩展 AdminGate 与新增中间件实现更细粒度的权限控制与安全策略。
附录:扩展与最佳实践
- 扩展中间件功能
- 新增自定义认证规则:在认证中间件前插入新中间件,复用 auth('admin') 守卫进行额外校验。
- 添加细粒度权限控制:扩展 AdminGate::canAccess,结合资源维度(如 targetId)进行判定。
- 添加自定义验证规则
- 在权限中间件中增加前置校验步骤,例如检查请求签名、设备指纹或风控标记。
- 实现细粒度权限控制
- 基于模块+动作+资源 ID 的组合判定,支持行级权限控制。
- 执行顺序建议
- 安全相关中间件(认证、权限、CSRF、限流)应置于业务中间件之前。
- 视图注入类中间件置于认证与权限之后,确保上下文完整。
- 错误处理机制
- 使用 HttpResponseException 短路返回,避免污染业务逻辑。
- 统一重定向到登录页或首页,并附带友好提示。
- 性能优化策略
- 缓存权限判定结果(如基于角色的菜单与按钮权限)。
- 避免在高频路径中进行昂贵计算或数据库查询。