tasks.md 12 KB

017 任务清单

2026-09-08 增量(实现中)

  • T23 骑手/商家 Apple、Google 独立凭证配置、角色绑定、会话签发及用户端兼容回归。
  • T24 兼容用户旧 LINE provider、无 provider 回调与旧/新绑定数据。
  • T25 更新三端接入文档、环境配置与 SQL 人工执行边界。
  • T26 JDK 21 定向测试、关联回归、模块构建与最终差异检查。
  • T27 业务 LINE 服务端 state 签发/单次消费、两条 code 入口校验及旧用户协议兼容。
  • T28 骑手/商家 App 页面、SDK、四语言和回跳 state 比对接入;源码路径待提供。

本轮验证记录

  • JDK 21 定向测试及 package:79 tests,0 failures/errors,所有 reactor 模块 SUCCESS。覆盖账号角色、短信绑定、用户原登录/注册、旧 LINE 协议、三端 audience、签名与 state。日志:ruoyi-admin/target/oauth-final-verification.log。
  • 另运行完整 mvn -pl ruoyi-admin -am package:ruoyi-system 83 tests 全通过,ruoyi-admin 419 tests 中 418 通过、1 error。仍是既有 PosOrderQsOprateControllerTest 未注入 UserService 导致 NPE,未修改该无关测试,T26 保留未勾选。日志:ruoyi-admin/target/oauth-regression.log。
  • 新业务账号绑定必须验证实际短信码,用户原校验行为保持兼容;固定短信码拒绝用例已先观察失败再验证修复。
  • 用户 App 源码未修改。业务 App 源码、真实渠道配置和真机端到端验证未完成;未执行任何数据库 SQL、部署或密钥轮换。
  • 既有实现已包含在 af8cc41;本轮增量保留工作区,尚未提交。

顺序执行;每步完成后编译验证。

  • T1 数据模型:updatesql/sql.md 加 info_user_oauth 建表(含 uk_provider_uid 唯一索引、idx_user_id)。
  • T2 实体:InfoUserOauth.java(@TableName=info_user_oauth,字段 id/userId/provider/providerUid/createTime)。
  • T3 mapper:InfoUserOauthMapper extends BaseMapper<InfoUserOauth>(无 XML)。
  • T4 LoginUserDto 加 provider 字段。
  • T5 JwtUtil.setToken(tokenKey, LoginUserDto) 加 provider claim(非空才写)。
  • T6 配置:application.yml 加 oauth.apple.clientId/jwks-url、oauth.google.clientId/tokeninfo-url、oauth.line.profile-url。
  • T7 依赖:ruoyi-admin/pom.xml 加 nimbus-jose-jwt。
  • T8 OAuthVerifyService:verify(provider, credential) → providerUid;Apple(nimbus 验 ES256)、Google(tokeninfo)、LINE(v2/profile),校 audience/iss/exp。
  • T9 DTO:OAuthLoginDto、OAuthBindDto。
  • T10 InfoUserController.oauthLogin:校验→查 oauth→命中签 token / 未命中缓存 tempKey 返 needPhone。
  • T11 InfoUserController.oauthBindPhone:取 providerUid + 验短信→关联/新建→写 oauth→签 token。
  • T12 编译验证(JDK21):ruoyi-admin + ruoyi-system + ruoyi-common。

联调待办(开发提供配置后)

  • 部署环境提供真实 Apple bundleId/clientId、Google clientId,以及 LINE_USER_CLIENT_SECRET、LINE_RIDER_CLIENT_SECRET、LINE_MERCHANT_CLIENT_SECRET;Secret 不写入仓库。
  • 部署前轮换 Git 历史中曾出现的旧 LINE Channel Secret。
  • 使用真实 Apple、Google、三套 LINE Channel token/code 完成端到端验证(Apple 需真机/测试机 Sign in with Apple)。
  • 三个前端 App 完成登录入口、首次绑手机、provider/回跳 scheme 分流及 i18n 联调。
  • 三端统一升级 state CSRF 协议:服务端签发并单次消费,App 保存发起值并在回跳时比对。

代码评审修复 (2026-07-30)

评审发现并修复(均已 JDK21 编译通过):

  • HTTP 超时:OAuthVerifyService.httpGet 原用 HttpClients.createDefault() 无超时,provider 慢/不可达会拖垮请求线程池 → 加 RequestConfig(连接 5s / 读取 10s / 获取连接 5s)。
  • 停用账号拦截:oauthBindPhone 用 getuser(phone) 只滤 del_flag、不滤 status,停用账号(status≠0)能通过三方绑定绕过停用 → 加 status!=0 拦截(与 lodeing / oauthLogin 已绑定路径一致),文案复用 no.user.stop。
  • Apple audience:原 aud.get(0) 在多 audience 时可能漏判 → 改 aud.contains(appleClientId)。
  • i18n 化(裸中文 → message key):新增 no.oauth.* 共 10 个 key,写入 5 份 properties(messages / zh_CN / zh_TW / en_US / vi);OAuthVerifyService 异常文案与 InfoUserController 提示全部走 MessageUtils.message,与 lodeing 风格一致。新增 key:
    • 控制器:no.oauth.provider.blank / needphone / tempkey.missing / tempkey.expired
    • 校验服务:no.oauth.credential.blank / provider.unsupported / token.invalid / token.expired / audience.mismatch / verify.fail(带 {0} 渠道名;异常详情仅记录在服务端日志,不返回客户端)

用户/骑手/商家 LINE 登录增量(2026-09-04)

  • T13 配置三组 LINE Channel:line_user、line_rider、line_merchant,共用 token/profile URL,分别配置 redirect URI 和 App scheme。
  • T14 OAuthVerifyService 按 provider 白名单选择对应 Channel ID、Secret、redirect URI,并使用完全相同的 redirect URI 换 token。
  • T15 共用 GET /auth/line/callback,接收 provider/code/state,按 provider 分流验证、绑定查询、token key 和 App 回跳。
  • T16 oauthLogin / oauthBindPhone 支持三个 LINE provider;骑手只绑定 userType=2,商家只绑定 userType=1/3/4/5,均不得自动创建。
  • T17 商家/骑手/子账号统一使用 tel_phone;业务层增加有效账号手机号唯一检查,修改时排除自身,软删除后允许复用。
  • T18 覆盖 addqishou、addshanghu、Bindingphone、setuser、平台新增/修改、stall/addOwner 及商家子账号新增入口。
  • T19 SQL:先预检 provider 和有效业务账号手机号冲突,再将现有 info_user_oauth.provider='line' 迁移为 line_user,并把业务账号 phone 补入 tel_phone,不清除原字段。
  • T20 更新 LINE 前端接入说明:原授权方式不变,三个端分别增加 provider 参数并使用对应 Channel ID/回跳 scheme。
  • T21 编写并运行定向测试,覆盖 provider 分流、角色限制、手机号唯一规则(2026-09-04:31 tests,0 failures/errors)。
  • T22 使用 JDK 21 编译 ruoyi-common、ruoyi-system、ruoyi-admin(2026-09-04 reactor package SUCCESS);真实 LINE 端到端联调保留为外部待办。

2026-09-04 另执行完整 reactor test:ruoyi-system 53 tests 全通过,ruoyi-admin 371 tests 中 370 通过、1 error。失败项为既有 PosOrderQsOprateControllerTest.newTasksContainOnlyPaidOrdersWaitingForRiderBeforeMerchantAcceptance 未注入 UserService 导致 NPE,与 017 修改文件及定向测试无关,本次不跨范围修改。

交付记录(2026-09-04):最终代码复核未发现剩余 Critical/Important;git diff --check 通过;数据库迁移未执行,须先运行 updatesql/sql.md 中两项冲突预检再由开发者手工执行;017 修改当前保留在工作区,尚未提交。

2026-09-24 后续增量待办:登录渠道与第三方名称展示

  • T29 为 info_user_oauth 增加可空字段 provider_display_name,并将迁移 SQL 记录到 updatesql/sql.md(不直接执行)。
  • T30 LINE 登录每次成功读取并刷新本渠道 displayName;读取失败保留旧值、不阻断登录。
  • T31 App 首次 Apple 授权取得 fullName 时传给后端;后端验证身份后保存到对应 Apple 绑定,历史无名称允许为空。
  • T32 用户资料接口与 App 分别展示原有昵称、本次登录渠道及对应第三方名称;昵称修改流程不变,空名称只显示渠道。
  • T33 编写并运行渠道切换、跨账号隔离、LINE 名称更新、Apple 首次/历史空值及 App 展示的定向验证。

实施记录(2026-09-28,test-202609v2):后端全部完成——OAuthIdentity 随凭证校验带回 displayName,OAuthLoginDto.fullName 承载 Apple 首次授权姓名,tempKey 缓存值三段式 provider@providerUid@displayName(空名称保持两段式,兼容旧值);JWT 新增 providerUid claim(gettoken 续签保真);getuserinfo 按会话渠道 + userId+providerUid 精确绑定回填 oauthProvider/providerDisplayName,旧会话无 providerUid 只展示渠道不任意挑绑定;LINE 直连与回调两条入口均在成功登录时刷新 displayName(空/未变保留旧值,失败不阻断)。定向测试 100 通过 + 全模块回归 759 tests 0 failures/0 errors。SQL 未执行(updatesql/sql.md 待手动执行);App 端展示联调待 App 源码接入(与 T28 同为外部待办)。

2026-10-08 增量:业务端改用账号密码绑定

  • T34 OAuthBindDto 新增 userName、password 字段(无校验注解)。
  • T35 oauthBindPhone 业务分支(*_rider/*_merchant)改为账号密码绑定:user_name + user_type + del_flag 查账号、RSA 解密比对、canOauthLogin 校验后写绑定;移除业务端短信路径;用户端手机号+短信逻辑逐行保留。
  • T36 新增 i18n key no.oauth.username.blank 写入 5 份 properties;其余提示复用现有 key。
  • T37 定向测试(先红后绿):业务密码绑定成功(免手机号)、密码错误/缺账号/缺密码拒绝、账号不存在不自动创建、已删除账号拒绝、用户端短信绑定回归;移除业务短信绑定与 tel_phone 多账号旧用例。
  • T38 JDK 21 定向测试与 ruoyi-admin 模块回归、编译验证;App 端账号密码表单与 LINE 回跳页联调为外部待办。

实施记录(2026-10-08,test-202609v2):TDD 先红后绿——RED 时 66 tests 中 10 个新/改用例如期失败(旧短信路径返回"账号不存在"等),实现后 66/66 通过;全模块回归 mvn -pl ruoyi-admin -am test 849 tests 0 failures/0 errors(含 BackendI18nBundleContractTest key 一致性契约)。已删除账号由查询 del_flag='0' 过滤按"账号不存在"拒绝,canOauthLogin 二次兜底(delFlag 异常数据返回"账号已停用")。本增量无数据库结构变更,无 SQL 待执行。App 端(骑手/商家)首次绑定页改为账号密码表单、LINE 回跳 needPhone=1 页面同改,为外部待办。

代码评审修复 (2026-10-08)

评审(6 维度核实)发现并修复,第二轮 TDD(RED 9 失败 → GREEN),修复后 InfoUserControllerTest 67/67、全模块回归 850 tests 0 failures/0 errors:

  • 业务端绑定不写设备信任:原实现 recordLogin 会把"设备 → 登记手机号"写入信任表,但业务端只验了密码(共享凭证)未验手机号;共享平板后续可经用户端 deviceConfirm 免短信冒用该手机号绑定/自动建会员账号(含钱包)。现仅用户渠道调用 recordLogin,业务绑定不写(成功用例断言 verifyNoInteractions(deviceMapper))。
  • userName 查询改 list() + 多行友好提示:原 getOne 在重名(平台 edit() 改名无唯一复查,库无唯一索引)时抛 TooManyResults 500 且已消耗 tempKey;现多行返回新 key no.oauth.username.duplicate(已加 5 份 properties)。
  • 去掉 userName 的 trim():与 shanglodeing/syslodeing 及建号路径的原串精确匹配一致,避免"带空格账号名日常可登录但绑定查不到"。
  • 测试有效性:成功用例提交密文与存储密文改为不同字符串(RSA 每次加密结果不同),防止实现退化为"密文直接相等比对"时测试仍然通过。

评审确认但不改(既有问题/产品决策,待定夺):

  • 平台 add()/edit() 存密码为客户端密文原样入库(add() 内 System.out.println("加密:"...) 处疑似遗留未做服务端加密);存量密码若非 RSA 密文则密码绑定永远失败(日常密码登录同样失败,属存量数据问题)。
  • 业务端绑定成为无速率限制的密码尝试入口(@Anonymous、tempKey 可随意发起换取);绑定永久且无解绑路径。建议后续加失败计数锁定或解绑能力(017 后续增量)。
  • 骑手日常登录 syslodeing 不校验 status,停用骑手可密码登录但三方绑定被拒(两端口径不一,既有行为)。
  • OAuth 绑定/登录不刷新 last_login_at(既有行为,影响"最近登录"展示)。
  • RSA 比对逻辑已有 4 份拷贝(登录×2/改密/绑定),建议后续抽公共服务。