Skip to content

feat(auth): OTP 注册引擎(待注册态 + 验证码) - #51

Closed
longsizhuo wants to merge 2 commits into
feat/resend-emailfrom
feat/otp-registration
Closed

longsizhuo wants to merge 2 commits into
feat/resend-emailfrom
feat/otp-registration

Conversation

@longsizhuo

Copy link
Copy Markdown
Member

ADR-001 规范邮箱子系统的引擎。栈在 #50(ResendEmailService)上。

范围(本 PR 只做引擎,不改认证主流程)

  • PendingRegistration:待邮箱验证的注册意图,进程内 Caffeine(15min TTL,不落库,放弃即自然消失)。
  • RegistrationService:
    • begin → pendingId
    • sendOtp(pendingId, email) → 6 位码,10min TTL,发信(Resend)
    • verifyAndConsume(pendingId, email, code) → 成功返回待注册意图并一次性消费

安全

  • 限次:5 次错码作废挑战,逼重发(防爆破)。
  • 邮箱绑定:验证时邮箱必须与发码对象一致,防"换个邮箱来撞码"。
  • 一次性:验证成功即消费待注册态 + OTP。
  • 全进程内、短 TTL、不落库。

验证

6 引擎测试(正确码消费 / 错码 / 邮箱不符 / 超次作废 / 无 pending 不发 / 无 OTP 不过);全量 278 通过。

下一步(wiring PR,改认证主流程)

loginByProvider → AuthOutcome(LoggedIn | NeedsEmailVerification);OAuthController 新用户分支跳验证页;RegistrationController 的 send-otp/verify-otp 端点;verify 通过后建号/关联 + 登入。之后前端两步页。

🤖 Generated with Claude Code

https://claude.ai/code/session_01RtSNVtrEkCsFVHrbt4Zjgi

Copilot AI review requested due to automatic review settings July 19, 2026 19:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

ADR-001 规范邮箱子系统的引擎部分(自包含可测):
- PendingRegistration:待邮箱验证的注册意图,进程内 Caffeine(15min TTL,不落库)
- RegistrationService.begin/sendOtp/verifyAndConsume:6 位码,10min TTL,
  限 5 次防爆破,邮箱与发码对象绑定(防换邮箱绕过),一次性消费
- 发信复用 ResendEmailService;发信失败返 false 供调用方作可重试用户错误

账号建号/关联的落地留给 wiring PR(改认证主流程,单独隔离)。
6 引擎测试;全量 278 通过。
review 发现的漏洞集中修:
- 【爆破封堵】attempts 累积在会话上、不被重发重置 → 6 位码爆破面恒为 5 次
- 【邮件轰炸】发信限流:会话至多 5 封、间隔 ≥60s;邮箱格式校验
- 【原子一次性】校验+消费在会话锁内完成,并发/双击只成功一次,不再重复建号
- 【邮箱验证不被架空】返回本次实际验证通过的 email(VerifiedRegistration),
  不再返回 provider 预填的未验证地址
- 【TTL 错配】单缓存可变会话,pending 与 OTP 同生命周期,会话 15min 不被重发刷新
- OTP 过期显式判定;String.format 指定 Locale.ROOT;SendResult 区分失败语义
- 可注入 Ticker,新增测试:重发不重置 attempts / 重发上限 / 冷却 / OTP 过期 /
  并发只消费一次 / 返回已验证邮箱

单实例内存态限制(多实例/native 需迁 Redis)与 pendingId 耗尽型 DoS(靠随机
UUID+短命+控制层 IP 限流)在类注释里写明。全量 283 测试通过。
@longsizhuo
longsizhuo force-pushed the feat/otp-registration branch from e6735c5 to 690ef3c Compare July 24, 2026 14:21
@longsizhuo
longsizhuo deleted the branch feat/resend-email July 24, 2026 14:25
@longsizhuo longsizhuo closed this Jul 24, 2026
longsizhuo added a commit that referenced this pull request Jul 24, 2026
review 发现的漏洞集中修:
- 【爆破封堵】attempts 累积在会话上、不被重发重置 → 6 位码爆破面恒为 5 次
- 【邮件轰炸】发信限流:会话至多 5 封、间隔 ≥60s;邮箱格式校验
- 【原子一次性】校验+消费在会话锁内完成,并发/双击只成功一次,不再重复建号
- 【邮箱验证不被架空】返回本次实际验证通过的 email(VerifiedRegistration),
  不再返回 provider 预填的未验证地址
- 【TTL 错配】单缓存可变会话,pending 与 OTP 同生命周期,会话 15min 不被重发刷新
- OTP 过期显式判定;String.format 指定 Locale.ROOT;SendResult 区分失败语义
- 可注入 Ticker,新增测试:重发不重置 attempts / 重发上限 / 冷却 / OTP 过期 /
  并发只消费一次 / 返回已验证邮箱

单实例内存态限制(多实例/native 需迁 Redis)与 pendingId 耗尽型 DoS(靠随机
UUID+短命+控制层 IP 限流)在类注释里写明。全量 283 测试通过。
longsizhuo added a commit that referenced this pull request Jul 24, 2026
* feat(auth): OTP 注册引擎——待注册态 + 验证码生成/校验/发信

ADR-001 规范邮箱子系统的引擎部分(自包含可测):
- PendingRegistration:待邮箱验证的注册意图,进程内 Caffeine(15min TTL,不落库)
- RegistrationService.begin/sendOtp/verifyAndConsume:6 位码,10min TTL,
  限 5 次防爆破,邮箱与发码对象绑定(防换邮箱绕过),一次性消费
- 发信复用 ResendEmailService;发信失败返 false 供调用方作可重试用户错误

账号建号/关联的落地留给 wiring PR(改认证主流程,单独隔离)。
6 引擎测试;全量 278 通过。

* fix(auth): 处理 #51 review——OTP 引擎安全重做

review 发现的漏洞集中修:
- 【爆破封堵】attempts 累积在会话上、不被重发重置 → 6 位码爆破面恒为 5 次
- 【邮件轰炸】发信限流:会话至多 5 封、间隔 ≥60s;邮箱格式校验
- 【原子一次性】校验+消费在会话锁内完成,并发/双击只成功一次,不再重复建号
- 【邮箱验证不被架空】返回本次实际验证通过的 email(VerifiedRegistration),
  不再返回 provider 预填的未验证地址
- 【TTL 错配】单缓存可变会话,pending 与 OTP 同生命周期,会话 15min 不被重发刷新
- OTP 过期显式判定;String.format 指定 Locale.ROOT;SendResult 区分失败语义
- 可注入 Ticker,新增测试:重发不重置 attempts / 重发上限 / 冷却 / OTP 过期 /
  并发只消费一次 / 返回已验证邮箱

单实例内存态限制(多实例/native 需迁 Redis)与 pendingId 耗尽型 DoS(靠随机
UUID+短命+控制层 IP 限流)在类注释里写明。全量 283 测试通过。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants