4.9 KiB
支付密码开发与验证记录
操作时间:2026-09-08 操作类型:扩展、修复 影响模块:用户设置、钱包密码、各业务端共用验证码与支付密码校验。
操作前后
设置中的支付密码原为未开放入口。现接通/settings/payment-password,读取当前钱包的payment_password_set,区分首次设置、旧密码修改、验证码找回;状态缺失进入错误重试,不能推断为未设置。密码限定六位数字、二次确认、请求中禁止重复提交,错误保留表单,仅收到changed=true才提示成功。
后端更新增加旧散列条件,防止并发覆盖;密码散列不进入SQL日志。输错计数与十五分钟锁定改为Redis原子脚本,五次失败后拒绝正确密码;缓存不可用也拒绝验证。验证码绑定客户端、手机号及用途,并在同一原子操作中校验和消费,防止并发重复使用。成功重置后清除本人锁定;若清锁失败,响应独立返回lock_cleared=false,页面明确区分密码已更新与锁仍可能生效。
短信限制
仓库仅有Mock验证码写入Redis,没有真实短信供应商。用户确认不知道现成配置路径;不重复索要密钥,也未擅自接入付费服务。接口保留原字段并新增delivery_mode=mock、delivery_status=not_sent及retry_after,关闭Mock时返回2410“短信验证服务尚未配置”。支付密码和注册页面不再把请求建立描述为短信已发送。首次设置与找回已通过隔离Mock联调,但真实手机收码仍未完成,不能计为生产可用短信流程。
代码与接口
apps/user_app/lib/ui/features/settings/payment_password_page.dart:新增页面;_load状态读取、_sendCode用途及冷却、_save明确响应确认。apps/user_app/lib/data/repositories/client_repository.dart:wallet、requestPaymentPasswordCode、setPaymentPassword增加会话保护,验证码手机号来自当前资料;不会接受页面传入钱包归属。apps/user_app/lib/domain/models/client_models.dart:可空密码状态及验证码请求结果模型,保持旧构造调用兼容。apps/user_app/lib/app/router.dart、ui/features/settings/settings_page.dart:受保护路由及设置入口;register_page.dart修正Mock提示。backend/api/internal/logic/common/client_wallet.go:SetPaymentPassword严格数字、锁感知验证、条件更新及清锁结果;原接口字段兼容。backend/api/internal/logic/common/payment_password_guard.go:抽出原共用校验并增加原子计数。backend/api/internal/logic/common/client_auth.go:短信未配置拒绝、交付元数据及验证码原子消费。- 新增
payment_password_test.go、payment_password_remote_test.go、verification_availability_test.go;Flutter新增test/data/payment_password_test.dart与test/ui/payment_password_page_test.dart。视觉工具增加31-payment,沿用明确测试数据,不从真实账户生成密码截图。
验证与风险
Flutter analyze及全量117项测试通过;页面8组320/360/390/430宽度、1.0/1.3文本缩放检查通过,已查看320放大截图无溢出。后端全量go test、go vet、API构建通过;新增短信不可用拒绝测试通过。
Web使用--pwa-strategy=none构建成功,Android调试包构建成功。浏览器加载新包后,支付密码深链跳转登录并在登录后回到原页面,读取真实已设置状态;空表单出现三处六位数字提示,找回模式正确切换为手机验证码,控制台无error/warn。未在真实用户钱包提交改密或发送验证码,成功变更由上述独立远程回滚测试覆盖。API进程39900监听12426,健康检查200;18571继续提供新Web产物。Android构建仍有既有插件Kotlin迁移提示,本轮未升级依赖,真机键盘及输入尚待验证。
显式开启HEQI_REMOTE_PAYMENT_PASSWORD_TEST=1的远程测试通过:独立临时用户与零余额钱包、首次设置、旧密码修改、验证码重置、错误格式、用途不匹配、16并发验证码仅一次成功、8并发错误密码触发五次锁定、重置解锁。数据库整体回滚后确认账户和钱包均不存在,仅清理本轮独立Redis键。没有修改真实账户支付密码、余额、数据库结构或远程缓存配置。
原子校验为共用逻辑,会影响所有调用支付密码或验证码的业务端,因此运行后端全量回归。Redis故障时相关验证不可用属于预期拒绝行为。网络中断后密码更新结果仍可能不确定,现有接口没有操作号查询;页面不把未知结果表述为密码未变更。
该子页没有独立一比一原稿,不把通用表单截图算作图31全量视觉验收。图31及全量App仍未完成严格1:1与全部功能验收,当前计数仍为16张部分实现、42张未完成对应完整页面、0张严格验收通过。