简介
本文件面向DouPHP的API授权控制系统,系统性说明API接口的认证机制、会话管理、用户身份识别、中间件拦截流程、接口级与方法级权限控制、限流防刷策略、密钥与安全配置,以及测试与调试方法。重点围绕以下实现:
- Token验证:基于不透明随机token的生命周期管理与校验
- 会话管理:通过Guard将解析出的用户上下文注入到当前请求生命周期
- 用户身份识别:会员ID与工作端身份的获取与校验
- 中间件拦截:UserAuthMiddleware与ThrottleMiddleware在HTTP边界的统一处理
- 权限控制:声明式鉴权模式(public/optional/required)与work_required子策略
- 限流防刷:按路由+IP维度的定向限流,超限返回429并附带Retry-After
- 安全配置:可信代理、Host白名单、响应头加固、会话Cookie硬化、限流存储路径
项目结构
API授权相关代码主要分布在以下位置:
- 中间件层:api/middleware/ 与 core/foundation/middleware/
- 鉴权门面与令牌服务:api/facade/Auth.php 与 core/service/user/ApiTokenService.php
- 鉴权模式配置:api/init/middleware.php
- 安全配置:config/security.php
- 路由与控制器:api/route/ 与 api/controller/
graph TB
Client["客户端"] --> MW_Auth["UserAuthMiddleware<br/>API会员鉴权"]
Client --> MW_Throttle["ThrottleMiddleware<br/>定向限流"]
MW_Auth --> Guard["Auth Facade<br/>api/facade/Auth.php"]
Guard --> TokenSvc["ApiTokenService<br/>core/service/user/ApiTokenService.php"]
MW_Throttle --> Store["ThrottleStore<br/>security.throttle.store"]
MW_Auth --> Policy["鉴权模式决策<br/>api/init/middleware.php"]
Controller["业务控制器<br/>api/controller/*"] --> Guard
Controller --> DB["数据库<br/>user / user_token"]
图表来源
- UserAuthMiddleware.php:34-93
- ThrottleMiddleware.php:31-90
- AbstractUserAuthMiddleware.php:124-168
- AbstractThrottleMiddleware.php:60-84
- Auth.php:197-255
- ApiTokenService.php:57-124
- middleware.php:33-146
- security.php:74-85
章节来源
- UserAuthMiddleware.php:34-93
- ThrottleMiddleware.php:31-90
- AbstractUserAuthMiddleware.php:124-168
- AbstractThrottleMiddleware.php:60-84
- Auth.php:197-255
- ApiTokenService.php:57-124
- middleware.php:33-146
- security.php:74-85
核心组件
- API会员鉴权中间件(UserAuthMiddleware)
- 从请求头提取Bearer token,调用auth('api')解析用户上下文,注入Guard,并在required模式下拒绝未登录或无工作端身份
- 定向限流中间件(ThrottleMiddleware)
- 对敏感路由按IP进行计数限流,超限返回429并设置Retry-After
- API鉴权门面(Auth)
- 实现GuardContract,提供id()/check()/guest()/workId()/work()等读接口,以及resolveUserContext/hydrate/checkLoginState等鉴权入口
- API令牌服务(ApiTokenService)
- 负责不透明随机token的签发、解析、吊销;仅存hash,支持过期清理与心跳刷新
- 鉴权模式配置(api/init/middleware.php)
- 声明式auth_modes与work_required,决定模块/动作的鉴权级别与工作端要求
- 安全配置(config/security.php)
- 可信代理、可信Host、安全响应头、限流存储路径、会话Cookie硬化
章节来源
- UserAuthMiddleware.php:34-93
- ThrottleMiddleware.php:31-90
- Auth.php:72-181
- ApiTokenService.php:26-158
- middleware.php:33-146
- security.php:51-85
架构总览
API请求进入后,先经过限流中间件进行配额检查,再进入鉴权中间件完成Token解析与用户上下文注入,最后交由控制器执行业务逻辑。
sequenceDiagram
participant C as "客户端"
participant T as "ThrottleMiddleware"
participant A as "UserAuthMiddleware"
participant G as "Auth Facade"
participant S as "ApiTokenService"
participant Ctrl as "业务控制器"
C->>T : HTTP请求
T->>T : 计算路由键与配额
alt 超限
T-->>C : 429 + Retry-After
else 未超限
T->>A : 放行
A->>G : resolveUserContext(bearerToken)
G->>S : resolve(token)
S-->>G : userId(或0)
G-->>A : 用户上下文(ok, userId, work...)
alt required且未登录
A-->>C : 401
else required且无work身份
A-->>C : 403
else 通过
A->>Ctrl : 继续处理
Ctrl-->>C : 业务响应
end
end
图表来源
- AbstractThrottleMiddleware.php:60-84
- ThrottleMiddleware.php:64-89
- AbstractUserAuthMiddleware.php:124-168
- UserAuthMiddleware.php:47-93
- Auth.php:197-255
- ApiTokenService.php:92-124
详细组件分析
UserAuthMiddleware:请求拦截、Token解析与用户状态检查
- 职责边界
- 从请求头读取Bearer token,调用auth('api')->resolveUserContext(token)解析上下文
- 将上下文注入Guard(hydrate),供后续控制器使用
- 根据鉴权模式(public/optional/required)与工作端策略(work_required)决定是否放行或拒绝
- 关键行为
- 未登录且required:返回401 JSON错误
- 已登录但无工作端身份且work_required:返回403 JSON错误
- optional/public:匿名访问或增强态访问均放行
- 配置来源
- 配置文件路径由configFile()返回,加载api/init/middleware.php中的auth_modes与work_required
flowchart TD
Start(["进入中间件"]) --> ReadMode["读取鉴权模式<br/>public/optional/required"]
ReadMode --> ModeCheck{"模式为public?"}
ModeCheck --> |是| Next1["直接放行"]
ModeCheck --> |否| Resolve["解析Token上下文"]
Resolve --> Ok{"ok=true?"}
Ok --> |否| Required{"required?"}
Required --> |是| Reject401["返回401"]
Required --> |否| Next2["放行可选登录态"]
Ok --> |是| Inject["注入用户上下文"]
Inject --> WorkReq{"work_required?"}
WorkReq --> |是| HasWork{"有work身份?"}
HasWork --> |否| Reject403["返回403"]
HasWork --> |是| Next3["放行"]
WorkReq --> |否| Next3
图表来源
- AbstractUserAuthMiddleware.php:124-168
- UserAuthMiddleware.php:47-93
- middleware.php:33-146
章节来源
- UserAuthMiddleware.php:34-93
- AbstractUserAuthMiddleware.php:124-168
- middleware.php:33-146
ThrottleMiddleware:API限流与防刷
- 职责边界
- 针对敏感路由(登录、注册、找回密码、短信验证码、公共写接口、防伪查询、LLM成本端点)按IP进行限流
- 超限返回429并设置Retry-After头
- 配额策略
- 通过throttleFor(module, action, sub)匹配精确/父段/模块根级别的配额表
- 默认不限流,仅显式配额的端点生效
- 存储与键
- 限流键默认module.action.ip
- 存储目录来自security.throttle.store
flowchart TD
Enter(["进入限流中间件"]) --> GetRoute["获取module/action/sub"]
GetRoute --> Lookup["查找配额表"]
Lookup --> Found{"找到配额?"}
Found --> |否| Pass["放行"]
Found --> |是| Check["统计次数/窗口"]
Check --> TooMany{"超过max?"}
TooMany --> |是| Reject["返回429 + Retry-After"]
TooMany --> |否| Hit["记录一次命中"]
Hit --> Pass
图表来源
- AbstractThrottleMiddleware.php:60-84
- ThrottleMiddleware.php:38-89
- security.php:74-77
章节来源
- ThrottleMiddleware.php:31-90
- AbstractThrottleMiddleware.php:60-84
- security.php:74-77
Auth Facade与ApiTokenService:Token验证与会话管理
- Auth Facade
- 暴露id()/check()/guest()/workId()/work()等读接口
- hydrate(context)将解析结果注入当前请求上下文
- resolveUserContext(token)组合checkLoginState与用户资料/工作端信息构建上下文
- checkLoginState(token)用于公开接口校验登录态
- ApiTokenService
- issue(userId, ip)签发64位十六进制随机token,持久化token_hash与过期时间
- resolve(token)校验token有效性,支持过期清理与last_active心跳刷新
- revoke/revokeAllForUser支持单设备与全部设备吊销
classDiagram
class Auth {
+id() int
+user() array
+check() bool
+guest() bool
+workId() int
+work() array
+hydrate(context) void
+resolveUserContext(token) array
+checkLoginState(token) array
}
class ApiTokenService {
+issue(userId, ip) string
+resolve(token) int
+revoke(token) void
+revokeAllForUser(userId) void
}
Auth --> ApiTokenService : "懒加载使用"
图表来源
- Auth.php:72-181
- Auth.php:197-255
- ApiTokenService.php:57-158
章节来源
- Auth.php:72-181
- Auth.php:197-255
- ApiTokenService.php:57-158
鉴权模式与工作端策略:接口级与方法级权限控制
- 接口级权限(模块/动作/子控制器)
- auth_modes定义每个模块或具体action的鉴权级别:public/optional/required
- 可通过更具体的键覆盖(如module/sub/action)
- 方法级权限(work_required)
- work_required列表中的模块/子控制器在required基础上额外校验工作端身份
- 典型场景
- 会员中心、订单、资金、售后、健康档案等私有数据模块设为required
- 内容浏览类模块设为optional,登录后增强
- 登录注册等公开接口设为public
- 工作端相关接口(如order/work、health/work)需具备work身份
章节来源
- middleware.php:33-146
- AbstractUserAuthMiddleware.php:124-168
路由与控制器集成
- 路由声明
- api/route/user.php定义了user模块下的GET/POST动作,包含登录注册、资料维护、微信子控制器与工作端入口
- 控制器基类
- BaseController承载API端专属逻辑,复用前台导航构建器,统一通过Facade与服务访问资源
章节来源
- user.php:35-70
- BaseController.php:38-60
依赖关系分析
- 中间件依赖
- UserAuthMiddleware依赖AbstractUserAuthMiddleware与api/init/middleware.php配置
- ThrottleMiddleware依赖AbstractThrottleMiddleware与security.throttle.store
- 鉴权链路
- UserAuthMiddleware -> Auth Facade -> ApiTokenService -> 数据库(user_token)
- Auth Facade -> UserService -> 工作端信息
- 安全配置
- security.php影响Request::ip()可信代理判定、安全响应头下发、会话Cookie属性、限流存储路径
graph LR
UAM["UserAuthMiddleware"] --> AUM["AbstractUserAuthMiddleware"]
UAM --> CFG["api/init/middleware.php"]
UAM --> AUTH["Auth Facade"]
AUTH --> ATS["ApiTokenService"]
TMW["ThrottleMiddleware"] --> ATM["AbstractThrottleMiddleware"]
TMW --> SEC["security.php(throttle.store)"]
AUTH --> DB["user_token / user"]
图表来源
- UserAuthMiddleware.php:34-93
- AbstractUserAuthMiddleware.php:124-168
- ThrottleMiddleware.php:31-90
- AbstractThrottleMiddleware.php:60-84
- security.php:74-85
章节来源
- UserAuthMiddleware.php:34-93
- ThrottleMiddleware.php:31-90
- security.php:74-85
性能与安全考量
- 性能
- 限流采用文件存储(ThrottleStore),建议部署在高可用文件系统或缓存后端;合理设置window与max避免频繁IO
- Token解析侧存在DB查询与哈希比较,注意索引与连接池配置
- last_active心跳更新限制为60秒内一次,降低写入压力
- 安全
- Token以sha256存储,防止泄露库可逆推有效凭证
- 使用hash_equals进行恒定时间比较,防范时序攻击
- 可信代理与Host白名单防止伪造IP与Host污染
- 安全响应头(X-Frame-Options、X-Content-Type-Options、Referrer-Policy、Permissions-Policy、HSTS)加固浏览器安全
- 会话Cookie启用HttpOnly、SameSite、Strict模式,减少XSS与CSRF风险
章节来源
- ApiTokenService.php:92-124
- security.php:51-85
故障排查指南
- 401未登录
- 检查Authorization头是否携带Bearer token
- 确认token格式为64位十六进制字符串
- 查看user_token表中是否存在有效且未过期的token_hash
- 参考:UserAuthMiddleware.php:77-82、Auth.php:197-229
- 403无工作端身份
- 确认路由命中work_required列表
- 检查用户是否具备work身份(workId>0)
- 参考:UserAuthMiddleware.php:87-92、AbstractUserAuthMiddleware.php:162-165
- 429请求被限流
- 检查对应路由是否在ThrottleMiddleware配额表中
- 查看security.throttle.store目录下的计数文件
- 参考:ThrottleMiddleware.php:64-89、AbstractThrottleMiddleware.php:60-84
- 登录态检查失败
- 使用check_login_state接口定位reason(missing_credential/invalid_credential)
- 参考:Auth.php:197-229
章节来源
- UserAuthMiddleware.php:77-92
- AbstractUserAuthMiddleware.php:162-165
- ThrottleMiddleware.php:64-89
- AbstractThrottleMiddleware.php:60-84
- Auth.php:197-229
结论
DouPHP的API授权控制系统通过“中间件前置拦截 + 声明式鉴权模式 + 令牌服务”的组合,实现了高内聚、低耦合的认证与授权能力。UserAuthMiddleware负责Token解析与用户上下文注入,ThrottleMiddleware提供细粒度的限流保护,Auth Facade与ApiTokenService共同完成不透明token的全生命周期管理。配合安全配置与路由声明,系统能够在保证安全性的同时具备良好的可扩展性与可维护性。
附录:测试与调试
- 测试登录态校验
- 调用user/check_login_state接口,传入Authorization: Bearer <token>,观察返回msg与reason字段
- 参考:Auth.php:197-229
- 测试鉴权模式
- 对public/optional/required不同路由分别发送带/不带token的请求,验证放行与拒绝行为
- 参考:middleware.php:33-146
- 测试工作端权限
- 对work_required路由,确保用户具备work身份,否则应返回403
- 参考:AbstractUserAuthMiddleware.php:162-165
- 测试限流
- 对受限路由高频请求,验证429与Retry-After头;检查security.throttle.store目录计数文件
- 参考:ThrottleMiddleware.php:64-89、security.php:74-77
- 调试Token生命周期
- 签发后检查user_token表新增行;解析时关注过期清理与last_active心跳更新
- 参考:ApiTokenService.php:57-124
章节来源
- Auth.php:197-229
- middleware.php:33-146
- AbstractUserAuthMiddleware.php:162-165
- ThrottleMiddleware.php:64-89
- security.php:74-77
- ApiTokenService.php:57-124