status: review created: 2026-07-26 complexity: 🟡中等
当前认证框架会在图形验证码和短信验证码响应中回显明文验证码,同时在服务端和浏览器控制台记录验证码;短信发送仍由始终成功的模拟方法完成,手机号验证码登录还存在发送与校验缓存键不一致的问题。
本变更是框架问题整改路线的第一阶段,只处理验证码链路,形成以下可验证结果:
prod 环境下,所有验证码响应都不包含 code 字段。forge-starter-message 通道发送;通道不可用时失败关闭,不写入可登录的验证码缓存,也不返回成功。dev/local Profile 且显式设置 FORGE_CAPTCHA_DEV_ECHO_CODE=true 时,允许本地模拟发送并回显验证码。captcha:sms:<phone> 缓存键。后续阶段按独立 SDD 变更推进,不纳入本 Spec:
forge-server/forge-framework/forge-starter-parent/forge-starter-auth/src/main/java/com/mdframe/forge/starter/auth/controller/AuthController.java#sendSmsCaptcha 暴露 POST /auth/captcha/sms。AuthController#getCaptcha 调用 IAuthService#getCaptcha,最终进入 CaptchaServiceImpl#generateGraphicCaptcha。SystemAuthServiceImpl#sendSmsCaptcha → CaptchaServiceImpl#sendSmsCaptcha。UsernamePasswordCaptchaAuthStrategy#validateCaptcha → ICaptchaService#validateAndDeleteSmsCaptcha。PhoneCaptchaAuthStrategy#doAuthenticate → UserLoadServiceImpl#validatePhoneCode。forge-server/forge-framework/forge-starter-parent/forge-starter-message/src/main/java/com/mdframe/forge/starter/message/sdk/MessageClient.java#send → forge-server/forge-framework/forge-starter-parent/forge-starter-message/src/main/java/com/mdframe/forge/starter/message/channel/SmsMessageChannel.java#send → SMS4J。本节涉及的实现文件为:
forge-server/forge-framework/forge-starter-parent/forge-starter-auth/src/main/java/com/mdframe/forge/starter/auth/service/impl/CaptchaServiceImpl.javaforge-server/forge-framework/forge-plugin-parent/forge-plugin-system/src/main/java/com/mdframe/forge/plugin/system/service/impl/UserLoadServiceImpl.javaforge-admin-ui/src/views/login/index.vue
CaptchaServiceImpl#generateCaptcha 在 DEBUG 日志打印 code。
CaptchaServiceImpl#validate 在 DEBUG 日志同时打印输入值和缓存值。
CaptchaServiceImpl#generateGraphicCaptcha 无环境判断地设置 CaptchaResult.code,并在日志打印答案。
CaptchaServiceImpl#validateSliderCaptcha 在日志打印 moveX 与 expectedX。
CaptchaServiceImpl#sendSmsCaptcha 先写 captcha:sms:<phone>,再调用始终返回 true 的 mockSendSms,响应始终设置 SmsCaptchaResult.code。
CaptchaServiceImpl#validateSmsCaptcha 在 DEBUG 日志打印输入值和缓存值。
UserLoadServiceImpl#validatePhoneCode 调用通用图形验证码接口,最终读取 captcha:phone_code:<phone>,与短信发送键不一致。
forge-admin-ui/src/views/login/index.vue#refreshCaptcha 和 #sendSmsCode 在开发构建中将响应验证码写入浏览器控制台。
工作区已有未提交的 CaptchaProperties 草稿及两个未使用 import;当前尚未改变运行行为,本变更在其基础上完成。
forge-starter-auth 是基础 Starter,直接依赖 forge-starter-message 会扩大所有认证使用方的依赖面;应通过小型 SPI 保持依赖方向。dev/local 且显式开关为真时生效。CaptchaResult.code 与 SmsCaptchaResult.code 为 null 时不参与 JSON 序列化。SmsCaptchaSender SPI,由认证服务负责生成、缓存和校验验证码,由组合层负责真实发送。forge-plugin-system 中增加 MessageClient 适配器,复用现有 SMS4J 通道。code,不能只返回 null 或空字符串。forge.captcha.dev-echo-code=true 只有在活动 Profile 包含 dev 或 local 时有效;prod 中配置为真也必须忽略。SensitiveDataUtil.maskPhone;异常日志保留堆栈但不得包含验证码或完整手机号。| 操作 | 表名 | 字段/索引 | 说明 |
|---|---|---|---|
| 无 | — | — | 本阶段不修改数据库结构或初始化数据 |
Redis 键协议调整:手机号登录停止读取 captcha:phone_code:<phone>,统一读取现有发送键 captcha:sms:<phone>。旧键为不可用路径产生的临时数据,无需迁移。
| 操作 | 接口 | 方法 | 变更内容 |
|---|---|---|---|
| 兼容收紧 | /auth/captcha |
GET | 默认及生产响应省略 data.code;图片、codeKey、有效期不变 |
| 兼容收紧 | /auth/captcha/sms |
POST | 默认及生产响应省略 data.code;无可用短信通道时返回 status=fail |
| 内部修复 | 登录接口手机号验证码模式 | POST | 校验键统一为 captcha:sms:<phone> |
前端目前仅在控制台读取 data.code,登录业务不依赖该字段,因此协议收紧不会影响正常图形验证码输入和短信倒计时。
forge-starter-auth:配置、DTO 序列化、验证码服务、短信发送 SPI、单元测试。forge-plugin-system:短信发送适配器、手机号验证码校验、单元测试及测试依赖。forge-starter-message:只复用公开 MessageClient/MessageChannel API,不修改其实现。forge-admin-server:增加显式环境变量映射,默认关闭开发回显。forge-admin-ui:删除两处验证码控制台输出。sys_sms_config 和第三方供应商,本地自动化只能通过 Stub 验证适配协议。code 自动填充验证码的非正式客户端将失效;这是预期安全收紧,不保留生产兼容开关。CaptchaServiceImpl 默认/开发/生产回显策略、真实通道成功失败、缓存回滚、一次性校验;响应 DTO JSON;消息适配器;手机号登录键统一;前端生产构建和敏感日志静态扫描。test-spec.md。dev/local 且显式开关开启时允许模拟回显。forge-starter-auth 定义 SmsCaptchaSender SPI,forge-plugin-system 提供 MessageClient 适配器,避免 Auth Starter 直接依赖消息实现。@JsonInclude(NON_NULL) 省略 code,不改变其他响应字段的全局 Jackson 行为。Environment.acceptsProfiles(Profiles.of("dev", "local")) 与 CaptchaProperties.devEchoCode 双门禁控制开发回显。SmsCaptchaResult.status 协议,通道不可用返回业务失败结果,不在匿名入口暴露供应商错误细节。| Task | 状态 | 实际改动文件 | 备注 |
|---|---|---|---|
| Proposal | 完成 | spec.md、tasks.md、test-spec.md、execution-log.md |
HARD-GATE 已确认,进入 apply |
| Task 1 | 完成 | CaptchaProperties、响应 DTO、SmsCaptchaSender、序列化测试 |
Red 2 条失败;Green 3 条通过,Auth Reactor 编译通过 |
| Task 2 | 完成 | CaptchaServiceImpl、ICaptchaService、核心行为测试 |
10 条验证码服务测试通过;Auth Starter 共 20 条通过;敏感日志扫描通过 |
| Task 3 | 完成 | MessageSmsCaptchaSender、UserLoadServiceImpl、System 插件测试 |
真实消息通道适配与手机号短信验证码一次性校验统一;System 4 条测试通过 |
| Task 4 | 完成 | Admin application.yml、登录页、本变更四份 SDD 文档 |
环境变量默认关闭;前端不再读取验证码答案;Admin 43 模块 package 和 UI build 通过 |
20.19.0 前端 8725 个模块生产构建成功;打包后 YAML 配置解析和精确敏感日志扫描通过。-am test 在进入 System 前被既有 datascope Surefire/JUnit 引擎配置阻断;System 已隔离验证。未配置真实短信供应商凭据,真实发送 E2E 按 Test Spec 跳过,不把 Stub 结果当作供应商验收。