Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

SMS 与消息模板

短信能力在 oak-general-business 里分成了两个层次:

  • 一层是“手机号登录、验证码发送”这类账号体系能力,它更多依赖 PassportToken
  • 另一层是“系统消息模板同步和消息类型映射”,这才是本章要重点讲的内容。

主要对象

这部分主要涉及:

  • SmsTemplate
  • MessageType
  • MessageTypeSmsTemplate

它们的关系很清晰:

  • SmsTemplate 保存某个系统下、某个短信渠道的模板信息;
  • MessageType 定义业务消息类型;
  • MessageTypeSmsTemplate 负责把业务消息类型映射到具体短信模板。

组件

短信相关组件并不多,但都很实用:

  • src/components/config/upsert/sms
  • src/components/passport/sms
  • src/components/user/login/sms
  • src/components/messageTypeSmsTemplate/list
  • src/components/messageTypeSmsTemplate/tab

也就是说,短信模块既包含模板管理,也直接连接着系统配置、登录方式配置和登录页本身。

config/upsert/sms 常用字段

这组组件编辑的是 System.config.Sms。当前源码里最关键的字段有:

  • mockSend
  • defaultOrigin
  • ali[]
  • tencent[]
  • ctyun[]

其中:

  • mockSend 打开后,发送验证码不会真的调用短信厂商接口
  • defaultOrigin 决定默认短信渠道

三类厂商配置的重点字段分别是:

1. 阿里云

  • accessKeyId
  • accessKeySecret
  • endpoint
  • apiVersion
  • defaultSignName

2. 腾讯云

  • secretId
  • secretKey
  • smsSdkAppId
  • region
  • endpoint
  • defaultSignName

3. 天翼云

  • accessKey
  • securityKey
  • endpoint
  • defaultSignName

源码里这组组件还有两个实现细节很值得直接告诉开发:

  • 三个渠道都是“数组配置”,可以添加多组帐号
  • 但真正默认发短信走哪家,还是看 defaultOrigin

所以项目里不要只配帐号不配 defaultOrigin,否则验证码发送链路很容易因为拿不到默认渠道而失败。

messageTypeSmsTemplate/list 常用参数

这是短信模板映射里最核心的一个管理组件,关键参数只有两个:

  • systemId
  • origin

但它内部已经做了不少事情:

  • ready() 时先拉当前系统、当前渠道下的 smsTemplate
  • 同时调用 features.template.getMessageType() 拉业务消息类型
  • 点击“同步模板”时直接调用 features.template.syncSmsTemplate(systemId, origin)
  • 新建映射时默认给一条 messageType + templateId
  • 同一种 messageType 在下拉里会被禁用,避免重复绑定

也就是说,这个组件并不只是一个普通 CRUD 表,它已经把:

  • 同步远端模板
  • 查看现有模板
  • 维护消息类型与模板映射

这些步骤合在一起了。

messageTypeSmsTemplate/tab 适合放在哪里

tab 组件的关键参数是:

  • systemId

它内部会按固定渠道自动分三栏:

  • ali
  • tencent
  • ctyun

并且每个页签里都挂一个 messageTypeSmsTemplate/list

这组组件最适合放在:

  • 系统后台页
  • 系统配置页
  • 平台级短信模板管理页

而不是登录页本身。

passport/sms 的真实职责

src/components/passport/sms/index.tsx 在文档里也值得单独写出来,因为它不是登录页,而是系统登录方式管理页里的一个“短信登录配置卡片”。

它当前接收的核心输入其实不是散装字段,而是三样东西:

  • passport
  • changeEnabled
  • updateConfig

其中 passport.config 里,这个组件真正会维护的是:

  • mockSend
  • defaultOrigin
  • templateName
  • codeDuration
  • digit

也就是说,账号体系里“短信登录”这一项真正依赖的,不只是系统级 System.config.Sms,还包括 passport 自己这份登录级配置:

  • 验证码模板名是什么
  • 验证码有效几分钟
  • 验证码是几位

components/passport/index.ts 的实现看,它还会在保存前主动检查配置完整性。如果启用了短信登录,但:

  • 没填 templateName
  • 没选 defaultOrigin

组件会直接给出 warning。也就是说,项目层如果复用整套 passport/* 管理页,很多“短信登录为什么不生效”的基础配置错误其实已经能在页面上提前暴露出来。

user/login/sms 常用参数

src/components/user/login/sms/index.ts 和 web 端渲染层当前最值得写进文档的参数有:

  • disabled
  • url
  • callback
  • allowPassword
  • allowEmail
  • allowWechatMp
  • setLoginMode
  • digit

其中真正影响登录流程的是:

  • url:登录成功后跳回哪里
  • callback:登录成功后的自定义回调
  • digit:验证码位数校验

allowPassword / allowEmail / allowWechatMp / setLoginMode 更偏小程序或多登录方式切换场景,决定这块表单是否要切到别的登录模式。

这组组件内部已经直接把两条关键链路接好了:

  • sendCaptcha() -> features.token.sendCaptcha('mobile', mobile, 'login')
  • loginByCaptcha() -> features.token.loginByMobile(mobile, captcha)

也就是说,项目层不应该再自己调用短信厂商 SDK,也不应该自己拼验证码登录接口。

还有两个很实用的源码细节:

  • 发送验证码有冷却时间,开发环境默认 10 秒,非开发环境默认 60 秒
  • 冷却时间戳会写到本地缓存,所以组件刷新后也不会立刻重新允许发送

一个很容易忽略的对齐点

user/login/smsdigitpassport/sms 里配置的验证码位数,本质上应该保持一致。

否则前端校验按 4 位、后台实际按 6 位生成时,就会出现:

  • 前端以为验证码合法,后台却认为长度不对
  • 或者前端根本不允许提交正确验证码

这也是为什么更推荐项目层直接复用公共 passport 配置页和公共登录组件,而不是把验证码位数写死在业务页里。

前端 feature 与 aspect

这一章主要依赖的前端入口是 features.template,其中和短信相关的方法有:

  • syncSmsTemplate(systemId, origin)
  • getMessageType()

对应的后端 aspect 则是:

  • syncSmsTemplate
  • getMessageType
  • sendCaptchaByMobile
  • sendCaptchaByEmail

其中:

  • syncSmsTemplate 会直接调用具体短信渠道实现,把远端模板同步到本地的 smsTemplate 对象里;
  • 验证码发送虽然前端统一走 features.token.sendCaptcha(...),但后端最终落到的是 sendCaptchaByMobile / sendCaptchaByEmail 这两个 aspect。

还有一个很容易漏掉的实现细节:

  • src/aspects/sms.ts 里的 syncSmsTemplate(...) 当前会按 templateCode 做“存在则 update,不存在则 create”
  • 但源码里“删除本地已失效模板”的逻辑目前是注释掉的

这意味着同步模板的真实语义更接近:

  • 增量更新
  • 增量新增

而不是“远端模板全量对齐本地模板”。

endpoint / watcher

短信模板这部分当前没有单独的 endpoint,也没有单独的 watcher。

这说明它的工作方式不是“被第三方平台回调驱动”,而是更适合通过后台管理动作或定期运维脚本来主动同步。

注入点

这一章的注入点在两个地方:

  • 前端通过 create(...) 注入 features.template
  • 后端通过 ogb0Aspects 注入 syncSmsTemplategetMessageType

所以只要你的项目已经接好了 oak-general-business,短信模板同步入口其实已经具备。

公共系统页已经有现成入口

oak-general-business/src/components/system/panel/web.pc.tsx 已经把短信模板页签接进系统后台了:

  • smsTemplate-list 页签直接包 messageTypeSmsTemplate/tab

这意味着如果项目本身已经复用 system/panel,往往不需要再额外写一页“短信模板管理台”。

项目中如何接入

短信能力在项目里主要通过两条线接入:

  • System.config.Sms 配渠道和签名;
  • features.templatefeatures.token 负责模板同步和验证码发送。

所以项目层通常不直接调短信 SDK,而是:

  • 管理台同步短信模板;
  • 登录/改密等页面调用 features.token.sendCaptcha(...)

真实项目里通常怎么组织

从当前 haina-busitaicang 的源码来看,没有再各自重写一套独立短信模板管理界面,更多是直接吃公共包和生成域能力。

这也符合这章的定位:

  • 系统配置页负责配 System.config.Sms
  • 公共系统页签负责模板同步和映射
  • 业务登录页只负责发验证码,不直接碰短信供应商细节

这种分法是最稳的。配置、模板、登录三层职责分得很清楚。

使用示例

1. 同步短信模板

src/features/template.ts 已经提供了直接入口:

await this.features.template.syncSmsTemplate(systemId, 'tencent');

对应的后台逻辑会调用 src/aspects/sms.ts,把模板同步到 smsTemplate 表。

1.1 在系统页里直接挂模板映射组件

如果你没有复用完整的 system/panel,最省事的做法通常是自己在系统配置页里直接挂:

<MessageTypeSmsTemplateTab
  oakPath={`$system-smsTemplate-${systemId}`}
  systemId={systemId}
/>

这样阿里云、腾讯云、天翼云三组模板映射就会自动分栏展示。

2. 发送短信验证码

项目登录页、改密页推荐统一走:

await this.features.token.sendCaptcha('mobile', mobile, 'login');
await this.features.token.sendCaptcha('mobile', mobile, 'changePassword');

这样实际短信渠道、签名、模板映射都由系统配置控制,项目层不需要关心底层短信厂商细节。

2.1 直接复用短信登录组件

如果项目登录页只想保留手机号验证码登录,最直接的包法通常就是:

<UserLoginBySms
  oakPath="#LoginBySms"
  url="/frontend/index"
  digit={6}
/>

如果这个页面本身只是登录弹窗,也可以不用 url,改传 callback

<UserLoginBySms
  oakPath="#LoginBySms"
  callback={() => this.setState({ visible: false })}
  digit={6}
/>

使用建议

最推荐的理解方式是:

  • 登录验证码的短信配置,看 Passport
  • 系统消息的短信模板映射,看 SmsTemplateMessageTypeSmsTemplate
  • 真正同步远端模板,走 features.template.syncSmsTemplate(...)

再补三条特别实用的注意事项:

  • defaultOrigin 一定要和实际配置过的 ali/tencent/ctyun 帐号对应上,否则验证码发送时虽然链路通了,最终还是会在 provider 选择这里出问题。
  • mockSend 只是不真的调用短信厂商,不代表验证码表不写入;开发环境下它仍然会创建 captcha 记录。
  • 模板同步当前不会自动删掉本地旧模板,所以如果厂商后台删过模板,项目侧最好结合运维规则人工检查一次映射关系。

把这三件事分开,短信模块就不会再显得混乱。