2026-04-30-REQ-USR-004.md
4.79 KB
req_id: REQ-USR-004 date: 2026-04-30
spec_ref: docs/superpowers/specs/2026-04-30-REQ-USR-004.md
REQ-USR-004 用户登录 Implementation Plan
Execution: Parent skill
feature-tddexecutes this plan task-by-task.
Goal: Phase A 实现 POST /api/usr/auth/login + 失败计数锁定 + JWT 双 token;Phase B 闭环 stub permitAll → authenticated。
Schema 改动
无。
文件变更清单
新增
- backend/src/main/java/com/xly/erp/module/usr/dto/LoginDTO.java
- backend/src/main/java/com/xly/erp/module/usr/vo/LoginVO.java
- backend/src/main/java/com/xly/erp/module/usr/vo/UserBriefVO.java
- backend/src/main/java/com/xly/erp/module/usr/security/LoginAttemptStore.java
- backend/src/main/java/com/xly/erp/module/usr/controller/AuthController.java
- backend/src/main/java/com/xly/erp/common/security/JwtAuthenticationEntryPoint.java
- backend/src/test/java/com/xly/erp/module/usr/security/LoginAttemptStoreTest.java
- backend/src/test/java/com/xly/erp/module/usr/controller/AuthControllerIT.java
修改
- common/security/JwtUtil.java — 加
signRefresh(userNo)+ 区分 access/refresh TTL - common/security/SecurityConfig.java — 重写路径规则 + 注册 entryPoint
- module/usr/mapper/UserMapper.java — 加
selectByUserName+updateLastLoginDate - module/usr/service/UserService.java + impl — 加
login(LoginDTO) - module/mod/service/impl/ModuleServiceImpl.java — 移除 stub fallback
- module/usr/service/impl/UserServiceImpl.java — 移除 stub fallback(create + update)
- ModuleControllerIT (4 处) + UserControllerIT (3 处) — 改 stub 期望
任务步骤
Phase A: 登录接口本体
Task 1: JwtUtil 加 signRefresh
- 加
Duration REFRESH_TTL = Duration.ofDays(30)+sign(userNo, ttl)通用方法 +signRefresh(userNo)包装;现有sign(userNo)走Duration.ofHours(8) - 单测:
signRefresh_signsWithLongerTtl - Commit:
feat(usr): jwtutil signRefresh REQ-USR-004
Task 2: LoginAttemptStore + 单测
- 新建
@Component LoginAttemptStore:recordFailure(userNo) → newCount/isLocked(userNo) → Optional<Long secondsRemaining>/clearFailures(userNo);常量MAX_ATTEMPTS=5/LOCK_DURATION=Duration.ofMinutes(15) - 单测 5 用例覆盖隔离 / 累加 / 锁定 / 自动解锁 / 清空
- Commit:
feat(usr): login attempt store + lock logic REQ-USR-004
Task 3: UserMapper 加 selectByUserName + updateLastLoginDate
-
@Select("SELECT ... FROM tUser WHERE sUserName = #{name}")User selectByUserName(String name) -
@Update("UPDATE tUser SET tLastLoginDate = #{ts} WHERE iIncrement = #{id}")int updateLastLoginDate(Integer id, LocalDateTime ts) - IT 2 用例
- Commit:
feat(usr): mapper selectByUserName + updateLastLoginDate REQ-USR-004
Task 4: LoginDTO + LoginVO + UserBriefVO + UserService.login + 单测
- 6 个 service 单测(spec 列表)
- Commit:
feat(usr): login service + dto/vo REQ-USR-004
Task 5: AuthController + IT (5 用例)
- 新建
AuthController @RequestMapping("/api/usr/auth"),@PostMapping("/login") - IT 5 用例覆盖 spec
- Commit:
feat(usr): auth controller + login it REQ-USR-004
Phase B: Stub 闭环
Task 6: SecurityConfig 收紧 + AuthenticationEntryPoint
-
JwtAuthenticationEntryPoint:未认证写 JSONResult.fail(20001, "未认证")+ status 200 - SecurityConfig:
- 移除
/api/mod/**+/api/usr/**permitAll - 加
/api/usr/auth/loginpermitAll anyRequest().authenticated()exceptionHandling(eh -> eh.authenticationEntryPoint(authEntryPoint))
- 移除
- 移除
// REQ-MOD-001 stub: see USR-004 follow-up注释 - Commit:
refactor(usr): tighten security to authenticated REQ-USR-004
Task 7: ModuleServiceImpl + UserServiceImpl 移除 stub fallback
-
ModuleServiceImpl#create:sCreatedBy = SecurityContextHelper.currentUserNo(),去掉?: stub.getStubUserNo();同UserServiceImpl#create+update - 不破坏
StubSecurityPropertiesbean 本身(仍可保留以防其他用途;本 REQ 仅停止 fallback 引用) - 单测调整:MOD-001
createWithValidDto_persistsWithStandardCols期望 sCreatedBy 不再是 STUB_ADMIN(而要在测试里手动 SecurityContextHolder.set principal);其他类似 - Commit:
refactor(usr): remove stub fallback in services REQ-USR-004
Task 8: 修改现有 stub IT 期望
- ModuleControllerIT 4 条:
postWithoutJwt_permitAllStub_returns200_andCreatedBySTUBADMIN/putWithoutJwt_*/deleteWithoutJwt_*/getWithoutJwt_*→ 改期望code=20001,DB 无新增行 - UserControllerIT 3 条:
postWithoutJwt_*/putWithoutJwt_*/getWithoutJwt_*→ 改期望code=20001 - 全量回归绿
- Commit:
test(usr): update stub regression to authenticated REQ-USR-004
提交计划
8 commits:6 feat + 2 refactor + 1 test(或合并为更少 commit 视进度)。