## 背景 #2766(PR #2771)接入了 better-auth `phoneNumber` 插件,但**只开了手机号+密码登录**:`sendOTP` 显式抛 `NOT_SUPPORTED`,因为平台目前没有任何短信发送能力——`NotificationChannel` 类型里声明了 `'sms'`(`packages/spec/src/contracts/notification-service.ts:19`),但 `service-messaging` 没有 sms channel 实现,也没有短信 provider 抽象。 无邮箱员工目前的密码找回只能靠管理员 `set-user-password`。OTP 首登/自助重置需要这块基建。 ## 诉求 1. **短信 provider 抽象与对接**:参照 email channel 的模式(`packages/services/service-messaging/src/email-channel.ts`,在 provider service 存在时注册 channel),定义 sender surface + 至少一个 provider 实现(阿里云短信 / Twilio,配置走 service-settings 模式)。 2. **messaging `sms` channel**:注册进 `messaging-service-plugin.ts` 的可插拔 channel 体系,`notify(channels:['sms'])` 可用。 3. **auth 侧接线**:`auth-manager.ts` 的 `phoneNumber({ sendOTP })` 从抛错改为经 sms channel 发送,打开: - `POST /phone-number/send-otp` + `/phone-number/verify`(OTP 登录/验证) - `POST /phone-number/request-password-reset` + `/phone-number/reset-password`(自助重置) 4. **导入联动**:`/admin/import-users` 的 `invite` 策略对有手机号的行支持"短信邀请"变体(无邮箱员工也能走首登自设密码路径)。 ## 安全要求(必须与功能同 PR) - **OTP 端点限流 + 按号码冷却**(SMS pumping 成本滥用是邮件渠道没有的攻击面);OTP 尝试次数上限(better-auth `allowedAttempts`)。 - OTP/验证码绝不落日志。 - 占位邮箱用户(`placeholder.invalid`)的短信路径与邮件拦截逻辑对齐。 ## 相关 - #2766 / PR #2771(phoneNumber 插件接入、占位邮箱、导入端点) - #2758(原始批量导入需求)
Activity
feat(messaging/auth): 短信基建(SMS provider + messaging sms channel)+ 手机号…
docs: services.sms reference + phone-number OTP authentication guide (#…
docs(auth): baseline better-auth 'role' boundary refs + regen referen…
docs(auth): 手机号登录、管理员用户管理与批量导入的文档更新 (#2811)
chore: bump objectui to cf2d56e32a11
fix(plugin-auth): count the per-number OTP send budget in the shared …
fix(spec): the error-code waiver reasons and the auth-feature registr…