简介
本开发文档面向 DouPHP 小程序用户认证模块,覆盖微信登录、手机号验证码登录、账号密码登录、用户注册、密码重置与会话管理(API Token)等关键能力。文档从系统架构、组件职责、数据流、安全策略与最佳实践等维度进行系统化说明,并提供流程图与时序图帮助开发者快速理解与扩展。
项目结构
小程序端认证相关代码主要分布在以下位置:
- API 控制器:处理小程序端 HTTP 请求,包括注册、登录、密码重置、微信登录、手机号获取、登出等。
- 前端控制器:负责 Web 端的登录/注册/找回密码流程(便于对比与复用服务)。
- 服务层:封装业务逻辑,如登录校验、注册创建、密码重置、用户认证与会话令牌签发。
- 基础设施:认证管理器、守卫、令牌服务等。
graph TB
subgraph "小程序/API"
UC["UserController"]
WC["WeixinController"]
end
subgraph "服务层"
LS["LoginService"]
RS["RegistrationService"]
PRS["PasswordResetService"]
UAS["UserAuthService"]
ATS["ApiTokenService"]
end
subgraph "基础设施"
AM["AuthManager"]
GG["GuestGuard"]
end
UC --> LS
UC --> RS
UC --> PRS
UC --> UAS
UC --> ATS
WC --> UAS
WC --> ATS
UAS --> AM
AM --> GG
核心组件
- 小程序用户控制器(UserController):统一入口,处理注册、账号密码登录、手机验证码登录、密码重置、个人资料修改、头像上传、第三方绑定、登出与会话状态检查。
- 微信小程序子控制器(WeixinController):实现小程序专属的微信登录、手机号解密获取、微信支付发起等能力。
- 登录服务(LoginService):封装凭据校验、手机号登录校验、自动建号与风控限制。
- 注册服务(RegistrationService):构建注册数据、发送验证码、创建用户、SNS 绑定、分销关系登记。
- 密码重置服务(PasswordResetService):生成重置令牌、发送邮件、校验与更新密码。
- 用户认证服务(UserAuthService):登录成功标记、账户锁定检测、IP 限流、审计日志。
- API 令牌服务(ApiTokenService):签发、吊销、批量吊销设备会话令牌。
- 认证管理器与守卫(AuthManager/GuestGuard):提供 auth('api') 等认证能力,支持 token 校验与会话状态检查。
架构总览
小程序认证采用“控制器 -> 服务 -> 基础设施”的分层设计:
- 控制器负责接收请求、参数校验、调用服务并返回统一响应。
- 服务层封装业务规则(验证码校验、限流、自动建号、分销关系、审计日志等)。
- 基础设施提供认证、令牌、存储、配置等通用能力。
sequenceDiagram
participant Client as "小程序客户端"
participant UC as "UserController"
participant LS as "LoginService"
participant UAS as "UserAuthService"
participant ATS as "ApiTokenService"
Client->>UC : POST /user/login_post
UC->>LS : validateLoginCredentials(用户名, 密码, IP)
LS-->>UC : {user, field, errors}
alt 验证通过
UC->>UAS : login(user, field)
UAS-->>UC : 登录成功标记
UC->>ATS : issue(userId, ip)
ATS-->>UC : token
UC-->>Client : {user, token, dou.auth}
else 验证失败
UC-->>Client : 错误信息
end
详细组件分析
微信登录(小程序)
- 流程要点:
- 小程序前端调用 wx.login 获取 code,后端通过 jscode2session 换取 openid/unionid/session_key。
- 根据 unionid/openid 查找或新建用户,必要时绑定手机号。
- 签发 API Token,记录登录次数与审计日志。
- 支持预加载模式(act=preload)用于提前判断手机号是否已存在。
- 安全措施:
- IP 限流防止暴力尝试。
- 账户锁定检测(基于 UserAuthService::isLocked)。
- 事务保护数据库写入,异常回滚并记录审计日志。
sequenceDiagram
participant WX as "微信服务端"
participant WC as "WeixinController"
participant DB as "数据库"
participant UAS as "UserAuthService"
participant ATS as "ApiTokenService"
WC->>WX : GET sns/jscode2session(code, appid, secret)
WX-->>WC : {openid, unionid, session_key}
alt 已存在用户
WC->>DB : 查询 user_sns.user_id
DB-->>WC : user
WC->>UAS : isLocked(user.id)
UAS-->>WC : locked?
alt 未锁定
WC->>DB : 更新 login_count
WC->>ATS : issue(userId, ip)
ATS-->>WC : token
WC-->>Client : {user_id, token, dou.auth.is_work}
else 已锁定
WC-->>Client : 账户锁定提示
end
else 不存在用户
WC->>DB : 新建用户 + 绑定 user_sns
DB-->>WC : new user
WC->>ATS : issue(newUserId, ip)
ATS-->>WC : token
WC-->>Client : {user_id, token, dou.auth.is_work}
end
手机号验证码登录
- 流程要点:
- 前端先获取短信验证码,提交时携带 verification_data(含 code/account/ontime)。
- LoginService::validatePhoneLogin 校验验证码与时间有效性,若手机号未注册则自动创建用户。
- 成功后签发 API Token 并返回用户信息。
- 安全措施:
- 验证码哈希比对与过期校验。
- 防爆破:多次失败后清空 verification session。
- 可选 CAPTCHA 校验(Web 端),API 端通过 IP 限流与审计日志防护。
flowchart TD
Start(["开始"]) --> GetCode["获取短信验证码"]
GetCode --> Submit["提交手机号+验证码"]
Submit --> Validate["校验验证码与时效"]
Validate --> Valid{"有效?"}
Valid --> |否| Error["返回错误并计数"]
Valid --> |是| FindOrCreate["查找或自动创建用户"]
FindOrCreate --> IssueToken["签发 API Token"]
IssueToken --> End(["结束"])
Error --> End
账号密码登录
- 流程要点:
- 控制器调用 LoginService::validateLoginCredentials 进行凭据校验。
- 通过后调用 UserAuthService::login 标记登录成功,并签发 API Token。
- 安全措施:
- 输入清洗与格式校验。
- 账户锁定检测与审计日志。
- 支持记住我(前端会话)与 API Token 双机制。
sequenceDiagram
participant Client as "小程序客户端"
participant UC as "UserController"
participant LS as "LoginService"
participant UAS as "UserAuthService"
participant ATS as "ApiTokenService"
Client->>UC : POST /user/login_post
UC->>LS : validateLoginCredentials(username, password, ip)
LS-->>UC : {user, field}
UC->>UAS : login(user, field)
UAS-->>UC : 登录成功
UC->>ATS : issue(userId, ip)
ATS-->>UC : token
UC-->>Client : {user, token, dou.auth.is_work}
用户注册
- 流程要点:
- 注册表单接口返回验证码 token 对与登录模式配置。
- 提交时按邮箱或手机号模式校验唯一性与格式。
- 若启用邮箱/短信验证码,需校验 verification_data 中的 code/account/ontime。
- 构建插入数据并创建用户,登记分销关系树。
- 成功后立即登录并签发 API Token。
- 安全措施:
- 字段校验(邮箱/手机号唯一性、密码强度与确认)。
- 验证码哈希比对与有效期控制。
- XSS 过滤与推广关系解析。
flowchart TD
A["获取注册表单"] --> B["选择邮箱或手机号"]
B --> C{"需要验证码?"}
C --> |是| D["发送验证码并校验"]
C --> |否| E["直接校验字段"]
D --> F["构建注册数据"]
E --> F
F --> G["创建用户"]
G --> H["登记分销关系"]
H --> I["签发 API Token"]
I --> J["返回用户信息"]
密码重置
- 流程要点:
- 小程序端通过 PasswordResetService::createPasswordResetTokenForEmail 生成重置令牌并发送邮件。
- Web 端支持两步式重置:先校验账户与验证码,再设置新密码。
- 重置成功后吊销该用户全部 API Token,确保旧会话失效。
- 安全措施:
- 邮件链接包含 uid/code,避免泄露敏感信息。
- 验证码时效与防重放。
- 密码使用 bcrypt 加密存储。
sequenceDiagram
participant Client as "客户端"
participant UC as "UserController"
participant PRS as "PasswordResetService"
participant Mail as "SiteMail"
participant ATS as "ApiTokenService"
Client->>UC : POST /user/password_reset_post(email)
UC->>PRS : createPasswordResetTokenForEmail(email)
PRS-->>UC : {ok, user, token}
alt 找到用户
UC->>Mail : sendUserPasswordResetMail(email, resetUrl)
Mail-->>UC : 发送结果
UC-->>Client : 成功提示
else 未找到用户
UC-->>Client : 404 错误
end
Note over Client,ATS : 重置密码后吊销全部 API Token
会话管理与登出
- Token 签发与校验:
- ApiTokenService::issue 为指定用户与设备签发令牌。
- AuthManager/GuestGuard 提供 auth('api')->checkLoginState(token) 等能力。
- 登出清理:
- UserController::logout 调用 ApiTokenService::revoke(bearerToken) 吊销当前设备令牌。
- 密码重置会调用 revokeAllForUser 吊销用户所有设备令牌。
- 自动登录:
- 小程序端在后续请求中携带 bearerToken,服务端据此识别用户身份。
classDiagram
class ApiTokenService {
+issue(userId, ip) string
+revoke(token) void
+revokeAllForUser(userId) void
}
class AuthManager {
+guard(name) Guard
+id() int
+check() bool
}
class GuestGuard {
+checkLoginState(token) array
+login(user) void
+logout() void
}
ApiTokenService --> AuthManager : "被调用"
AuthManager --> GuestGuard : "管理守卫"
依赖关系分析
- 控制器依赖服务:UserController 依赖 LoginService、RegistrationService、PasswordResetService、UserAuthService、ApiTokenService。
- 微信登录依赖外部服务:WeixinController 调用微信开放平台接口(jscode2session、手机号解密)。
- 认证基础设施:AuthManager 与 GuestGuard 提供统一的认证能力,ApiTokenService 负责令牌生命周期管理。
- 配置驱动:登录模式、验证码开关、短信/邮箱配置来自 config/config.php。
graph LR
UC["UserController"] --> LS["LoginService"]
UC --> RS["RegistrationService"]
UC --> PRS["PasswordResetService"]
UC --> UAS["UserAuthService"]
UC --> ATS["ApiTokenService"]
WC["WeixinController"] --> UAS
WC --> ATS
UAS --> AM["AuthManager"]
AM --> GG["GuestGuard"]
CFG["config/config.php"] --> UC
CFG --> WC
性能与并发考虑
- 验证码与限流:
- 登录接口使用 IP 限流与账户锁定检测,降低暴力破解风险。
- 验证码校验包含时间与哈希比对,减少无效请求。
- 数据库事务:
- 微信登录与绑定操作使用事务,保证一致性;异常回滚并记录审计日志。
- 令牌管理:
- 签发与吊销操作应高效;建议结合缓存层优化频繁校验场景。
- 外部接口:
- 微信接口调用需做好超时与重试策略,避免阻塞主线程。
故障排查指南
- 微信登录失败:
- 检查 appid/appsecret 配置是否正确。
- 查看审计日志中 LOGIN_FAIL 与对应详情(如 WX_CODE_INVALID、WX_UNIONID_MISSING)。
- 验证码错误:
- 核对 verification_data 中的 code/account/ontime 是否与发送一致且未过期。
- 检查验证码发送频率与过期时间配置。
- 账户锁定:
- 通过 UserAuthService::isLocked 检测账户是否处于锁定状态,等待解锁或联系管理员。
- 令牌失效:
- 确认客户端是否正确携带 bearerToken。
- 检查是否执行了 logout 或密码重置导致令牌被吊销。
结论
DouPHP 小程序认证模块通过清晰的分层设计与完善的安全措施,实现了微信登录、手机号验证码登录、账号密码登录、注册与密码重置等核心能力。借助 ApiTokenService 与会话管理,保障了多设备会话的一致性与安全性。建议在实际使用中遵循安全最佳实践,持续监控与优化性能与稳定性。
附录:接口与数据流速查
- 注册表单:GET /user/register
- 返回:captcha_token、storage_captcha_token、promotion_user_sn、sns_token、login_mode、mail_username、sms_accessKeyId
- 参考路径:api/controller/user/UserController.php:166-185
- 注册提交:POST /user/register_post
- 校验:email/mobile 唯一性、password 强度与确认、验证码(可选)
- 返回:user、dou.auth.is_work
- 参考路径:api/controller/user/UserController.php:193-281
- 账号密码登录:POST /user/login_post
- 校验:username/password、IP 限流
- 返回:user、token、dou.auth.is_work
- 参考路径:api/controller/user/UserController.php:298-324
- 手机号验证码登录:POST /user/login_phone_post
- 校验:mobile、verification、verification_data
- 返回:user、token、dou.auth.is_work
- 参考路径:api/controller/user/UserController.php:341-371
- 密码重置:POST /user/password_reset_post
- 行为:生成重置令牌并发送邮件
- 参考路径:api/controller/user/UserController.php:391-414
- 微信登录:POST /user/weixin/login
- 行为:jscode2session、绑定/新建用户、签发 token
- 参考路径:api/controller/user/WeixinController.php:108-379
- 登出:POST /user/logout
- 行为:吊销当前设备 token
- 参考路径:api/controller/user/UserController.php:543-547