# Quickstart: 设备信任免绑手机号 > 2026-10-30 增量见文末:同设备换手机号解绑。五字段数据库方案已确认;后端已实现,用户已确认测试库 SQL 执行完成;数据库并发及 App 联调待执行;涉及换号及已有绑定直登的旧描述以增量节为准。 **Date**: 2026-09-20 | **Spec**: [spec.md](spec.md) | **契约**: [contracts/api-contract.md](contracts/api-contract.md) ## 前置条件 1. **数据库**:`updatesql/sql.md` 中"2026-09-20 设备绑定手机号信任表"DDL 已由开发者手动执行(本任务只追加脚本不执行)。 2. **Redis**:本地 Redis 可用(临时凭证依赖)。 3. **JDK**:临时设置(不改全局配置,Git Bash 示例): ```bash export JAVA_HOME="$HOME/.jdks/graalvm-jdk-21.0.12+7.1" export PATH="$JAVA_HOME/bin:$PATH" ``` 4. **短信万能码**:沿用现网 `8888`(测试不必真实收码)。 ## 自动化验证(测试命令) ```bash # 全量跑本 feature 测试(DeviceTrust + 分支/确认流程) mvn -pl ruoyi-admin -am test -Dtest='DeviceTrust*Test' -Dsurefire.failIfNoSpecifiedTests=false # 编译校验(含 ruoyi-system) mvn -pl ruoyi-admin -am compile ``` 预期:全部通过。已知基线红测试与本 feature 无关(flash payType 白名单,见项目记忆)。 ## 手动端到端场景(curl 模拟,配合契约文档 §6) 服务起在本地(默认 8080,按实际部署调整)。`DEV=dev-uuid-001` 为模拟设备标识。 ### 场景 A:建立信任 → 三方免绑 ```bash # 1. 手机号短信登录(万能码 8888),带 deviceId —— 建立/刷新设备信任 curl -X POST http://localhost:8080/infouser/user/lodeing \ -H 'Content-Type: application/json' \ -d '{"phone":"0987654321","code":"8888","deviceId":"dev-uuid-001"}' # 预期:登录成功 token;DB: info_user_device 出现 device_id=dev-uuid-001, phone=0987654321 # 2. 查库确认(人工) # SELECT * FROM info_user_device WHERE device_id='dev-uuid-001'; # 3. 用"新的"三方身份登录(credential 用测试渠道或 mock) curl -X POST http://localhost:8080/infouser/user/oauthLogin \ -H 'Content-Type: application/json' \ -d '{"provider":"google","credential":"","deviceId":"dev-uuid-001"}' # 预期:data = {status:"deviceConfirm", tempKey:"...", maskedPhone:"098****4321"} # 4. 一键确认(免短信) curl -X POST http://localhost:8080/infouser/user/oauthDeviceConfirm \ -H 'Content-Type: application/json' \ -d "{\"tempKey\":\"<第3步tempKey>\",\"deviceId\":\"dev-uuid-001\"}" # 预期:返回 token + user(即 0987654321 的账号);info_user_oauth 新增 google 绑定行 ``` ### 场景 B:兼容性回归(必须零差异) ```bash # 不带 deviceId 的老版本行为 curl -X POST http://localhost:8080/infouser/user/oauthLogin \ -H 'Content-Type: application/json' \ -d '{"provider":"google","credential":"<另一个新身份>"}' # 预期:{status:"needPhone", tempKey}(原样) ``` ### 场景 C:异常路径 - tempKey 过期(>5 分钟再确认)→ `no.oauth.tempkey.expired` - 确认时换 deviceId(`dev-uuid-999`)→ `no.oauth.device.mismatch`,不产生绑定 - 信任手机号账号停用(先手动 UPDATE status)→ `no.user.stop` ### 场景 D:LINE 回调 浏览器打开 authorize URL(`state=dev-uuid-001`)→ 走完 LINE 同意 → 观察 302 回跳参数: - 已信任:`deviceConfirm=1&tempKey=...&maskedPhone=098****4321` - 无信任(state 换成新值):`needPhone=1&tempKey=...` ## 通过标准 - 自动化测试全绿;场景 A/B/C/D 行为与 [contracts/api-contract.md](contracts/api-contract.md) 逐条一致。 - 老版本兼容:所有不带 deviceId 的请求与改造前行为完全一致。 ## 2026-10-30 增量验收清单(数据库及 App 场景待联调) 前置:用户已确认五字段建表方案,待开发者手动创建 info_user_oauth_device;旧绑定清理由开发者另行安排。后端已实现,建表后执行以下真实环境验收。 - 同设备 A→B:分别通过手机号验证码登录、第三方验证码绑号触发,核对旧绑定及全部设备关联删除、新绑定保留、设备用户和返回 token 均为 B。 - 同号、验证码错误、账号停用、事务回滚:旧绑定保持;无有效 deviceId 的旧版本无设备解绑动作。 - 多设备同一身份:关联可为多行,第三方身份绑定仍仅一行;全局解绑后其他设备重新绑定。 - 同账号设备2登录:设备1旧 token 请求返回401,账号及业务数据保留。 - LINE 回调、直连 OAuth、绑定容错分支、一键确认均覆盖;商家/骑手渠道不参与用户端解绑。 - MySQL 并发验证设备换号与第三方绑定交错、绑定归属变化、首次设备并发创建;不误删新绑定、不返回旧用户 token;换号前生成的确认凭证必须被拒绝。 本轮已执行后端定向单元测试;数据库迁移、MySQL 并发/回滚、双设备/App 联调尚未执行。最终命令和结果见下方。 ### 2026-10-30 实际验证记录 JDK:`C:\Users\99029\.jdks\graalvm-jdk-21.0.12+7.1`,只修改当前命令环境。 ```powershell mvn -q -pl ruoyi-admin -am '-Dtest=DeviceBindingSwitchTest,DeviceTrustServiceTest,DeviceTrustFlowTest,InfoUserControllerTest,LineCallback*Test,MerchantSessionAuthAnnotationTest' '-Dsurefire.failIfNoSpecifiedTests=false' package ``` 结果:exit 0;130项测试,0失败、0错误、0跳过;ruoyi-admin 及依赖模块打包通过。日志:`ruoyi-admin/target/029-build.log`(本地构建产物,不纳入 Git)。`git diff --check` 通过。 覆盖:手机号/验证码绑定 A→B、只删旧账号本设备关联、同账号不删、错误验证码不解绑、冲突绑定不返回其他账号、过期/换号前确认拒绝、已删除绑定不能复活、LINE 冲突回跳、无设备兼容、商家/骑手回归。加锁顺序回归先在旧流程失败,再随调整通过;这是调用顺序验证,不是真实数据库死锁复现。 未执行:数据库建表、历史绑定清理、MySQL 并发/回滚集成、真实 Apple/Google/LINE 授权及 App 双设备联调、部署。用户随后要求 040 注销翻悔期与 029 一并提交;两个功能按当前工作区组合验证。 后续状态:2026-10-30 用户确认建表 SQL 已在测试环境执行;未由本次工具连接数据库复核。历史绑定清理、MySQL 并发与 App 联调不据此视为完成。 ## 2026-10-30 联合提交前验证 用户要求 029 同设备换号解绑与 040 注销翻悔期一并提交。使用 JDK21 执行: ```powershell mvn -q -pl ruoyi-admin -am '-Dtest=UserCancellationServiceTest,UserCancellationMapperTest,DeviceBindingSwitchTest,DeviceTrustServiceTest,DeviceTrustFlowTest,InfoUserControllerTest,LineCallback*Test,AuthAspectTest,MerchantSessionAuthAnnotationTest' '-Dsurefire.failIfNoSpecifiedTests=false' package ``` 结果:143 项测试,0 失败、0 错误、0 跳过;package 成功,git diff --cached --check 通过。日志:ruoyi-admin/target/029-040-package.log。 未执行真实 MySQL/Redis 并发集成、App 联调及环境发布。用户已确认 029 关联表 SQL 在测试库执行;040 cancellation_deadline_at 字段迁移是否已执行尚未单独确认。