2026-05-08-REQ-USR-004.md 3.08 KB

req_id: REQ-USR-004 date: 2026-05-08 round: 1

reviewer: superpower-code-reviewer

Review: REQ-USR-004 — round 1

结论

request-changes (approve / request-changes)

Must-fix

  • [high] sql/migrations/V1_initial_schema.sql:108 — uk_usr_user_username 是全库唯一索引,规格要求多租户隔离,同一 sUsername 应允许出现在不同 brand(sBrandsId)中,唯一性应为 (sUsername, sBrandsId) 复合唯一,否则第二个 brand 的同名用户插入时会触发唯一约束违反(建议:新增 V2fix_username_unique_per_tenant.sql,DROP 旧索引并 CREATE UNIQUE INDEX uk_usr_userusername_tenant ON usr_user (sUsername, sBrandsId);同步更新 docs/03)
  • [medium] backend/src/main/java/com/example/erp/module/usr/service/impl/AuthServiceImpl.java:71 — UpdateWrapper 使用裸字符串列名("sId", "iLoginFailCount", "tLockUntil", "tLastLoginDate"),与项目其余代码 LambdaQueryWrapper 不一致,列重命名时不会编译报错(建议:改为 LambdaUpdateWrapper 使用方法引用,同时在 AuthServiceTest @BeforeAll 初始化 TableInfo 以支持单元测试)
  • [medium] backend/src/main/java/com/example/erp/module/usr/service/impl/AuthServiceImpl.java:118 — refresh() 只检查 user==null 和 bIsDisabled=1,未检查 tLockUntil;锁定账号可通过持有的 refresh token 持续获取新 access token 长达 7 天,绕过防暴力破解机制(建议:追加 tLockUntil 检查,并新增 refresh_lockedUser_throws40103 测试)

Nice-to-have

  • docs/05-API接口契约.md:49 — API 契约为 POST /api/auth/login 列出了 40400(公司编号不存在),但规格和实现均正确使用 40100(防枚举),契约文档应删除 40400 行
  • backend/src/main/java/com/example/erp/common/util/JwtUtil.java:72 — doParse() 对 access token 过期也抛 40103(REFRESH_TOKEN_INVALID),语义污染;建议区分 access/refresh 解析路径或使用更通用的 token 失效码
  • backend/src/main/java/com/example/erp/module/usr/service/impl/AuthServiceImpl.java:57 — Integer.valueOf(1).equals(user.getBIsDisabled()) 写法冗长,可简化为 user.getBIsDisabled() != null && user.getBIsDisabled() == 1
  • backend/src/main/java/com/example/erp/module/usr/service/impl/AuthServiceImpl.java:110 — refresh() 和 getBrands() 为只读操作,应加 @Transactional(readOnly = true)
  • backend/src/test/java/com/example/erp/module/usr/AuthServiceTest.java:93 — login_accountLocked_throws40102WithRemainingMinutes 只断言 message.contains("分钟"),未验证具体分钟数

反例 / 测试覆盖缺口

  1. 缺少「锁定期内再次尝试登录仍返回 40102」测试(验收标准第 3 条后半段)
  2. 缺少 refresh_lockedUser_throws40103 测试(见 must_fix 第 3 条)
  3. 缺少多租户隔离集成测试(验收标准第 7 条):同一用户名、不同 brandId 各自独立
  4. 前端 LoginPage.test.tsx 缺少登录失败时 message.error 展示的断言
  5. request.ts 的 401 自动刷新 pendingQueue 并发重试场景无测试覆盖
  6. JwtUtilTest 缺少 generateRefreshToken claims 验证正向测试