52 lines
6.1 KiB
Markdown
52 lines
6.1 KiB
Markdown
# 腾讯云验证码短信接入
|
|||
|
|
|
||
|
|
本项目的 SaaS 家庭端、管理端、设备绑定入口和小程序原生登录共用一套服务端短信发送器。前端只提交手机号、图片验证码和短信验证码,不持有腾讯云密钥。服务端沿用现有 6 位随机码、5 分钟有效、一次性消费、最多 5 次验证、60 秒重发间隔、每手机号每小时最多 5 次,以及会话和 IP 限流。
|
||
|
|
|
||
|
|
## 腾讯云侧准备
|
||
|
|
|
||
|
|
在 [短信控制台](https://console.cloud.tencent.com/smsv2) 开通国内短信,并创建短信应用、实名认证资质、已审核通过的签名和“验证码短信”正文模板。模板支持验证码变量,以及可选的有效分钟数变量;参数顺序由下方 `template_params` 配置。取得 SDK AppID、签名**名称**、各用途的模板 ID。在 [API 密钥管理](https://console.cloud.tencent.com/cam/capi) 创建仅供服务端使用的密钥,并给该身份授予发送短信所需的最小权限。
|
||
|
|
|
||
|
|
## 服务端单文件配置(推荐)
|
||
|
|
|
||
|
|
填写 `deploy/server/tencent-sms-template/tencent-sms.json.example`,保存为 `tencent-sms.json`,上传到服务器 `/etc/data-terminal-cloud/voice-runtime/tencent-sms.json`。其中包含 SecretId、SecretKey、短信 SDK AppID、签名名称和四个模板 ID:`login`、`register`、`change_password`、`change_phone`。AppKey 不使用。
|
||
|
|
|
||
|
|
默认模板参数只有验证码。若正文还包含有效分钟数,在同一个 JSON 文件中设置 `"template_params": {"register": ["code", "expires_minutes"]}`;按数组顺序传入验证码和实际有效期 `5`,不填写真实验证码。当前腾讯云账号的注册模板已确认是两个变量,另外三个模板均为一个变量。
|
||
|
|
|
||
|
|
现有服务器 Compose 已只读挂载该目录。API 和 worker 默认自动读取容器内 `/run/secrets/voice-runtime/tencent-sms.json`;不存在时沿用原有环境变量配置。也可用 `TENCENT_SMS_CONFIG_FILE` 指定其他容器内绝对路径,显式指定的文件缺失会拒绝启动。单文件存在时,其 `enabled` 和短信配置优先于旧版环境变量;callbacks 等其他服务不读取此文件。支持 UTF-8 BOM,格式错误的报错不会包含密钥内容。
|
||
|
|
|
||
|
|
部署本次服务端代码及 `000070_sms_purpose` 迁移后,重启 API 和 worker 加载该文件。不会因为仅上传文件就自动启用或热加载。
|
||
|
|
|
||
|
|
家庭端/小程序的注册与登录共用入口,服务端按手机号凭据是否存在选择注册或登录模板。管理端登录始终用登录模板。SaaS 的“忘记密码”发送 `purpose=CHANGE_PASSWORD`,使用修改密码模板;验证后沿用已有的登录会话与密码设置流程。请求号同时绑定手机号和请求用途,不能跨用途重放发送。
|
||
|
|
|
||
|
|
`change_phone` 已支持独立配置和在发送器中按用途选模板;当前没有更换手机号的业务接口和页面,登录接口不接受 `CHANGE_PHONE`。新增换号功能时必须单独验证当前账号、旧/新手机号并绑定验证用途,不能把换号验证码当登录凭据。
|
||
|
|
|
||
|
|
## 兼容旧版环境变量与分文件配置
|
||
|
|
|
||
|
|
API 与 worker 使用同一组配置。生产环境把 `SecretId` 和 `SecretKey` 分别放在只读密钥文件中,不放进仓库、前端、小程序、公开日志或 Compose 明文环境变量:
|
||
|
|
|
||
|
|
```dotenv
|
||
|
|
ONBOARDING_SMS_LOGIN_ENABLED=true
|
||
|
|
ONBOARDING_SMS_PROVIDER=tencent
|
||
|
|
TENCENT_SMS_SECRET_ID_FILE=/run/secrets/voice-runtime/tencent-sms-secret-id
|
||
|
|
TENCENT_SMS_SECRET_KEY_FILE=/run/secrets/voice-runtime/tencent-sms-secret-key
|
||
|
|
TENCENT_SMS_SDK_APP_ID=<短信应用 SDK AppID>
|
||
|
|
TENCENT_SMS_SIGN_NAME=<审核通过的签名名称>
|
||
|
|
TENCENT_SMS_TEMPLATE_ID=<审核通过的验证码模板 ID>
|
||
|
|
```
|
||
|
|
|
||
|
|
仍须保留原有 `ONBOARDING_MASTER_KEY`、`ONBOARDING_ENTRY_URL` 和可信代理配置。`ONBOARDING_SMS_PROVIDER=gateway` 保留原自建 HTTPS 网关模式。未配置完整时不要开启 `ONBOARDING_SMS_LOGIN_ENABLED`;启动校验会拒绝缺少必需参数的配置。当前腾讯云适配器只向 `+86` 中国大陆手机发送,避免把国内模板误用到国际号码。
|
||
|
|
|
||
|
|
腾讯云 SDK 使用官方 API v2021-01-11 的 `SendSms`,每次传一个手机号,并按对应用途配置传入验证码及可选的有效分钟数参数;检查单号码 `SendStatusSet.Code == "Ok"` 后才将平台短信挑战标记为已发送。`SessionContext` 放入挑战 UUID 供发送记录关联,但腾讯云并不以它作为幂等键。平台对于超时等不确定结果**不会自动重试**,避免重复发送和计费;用户需等待重发间隔后重新申请。
|
||
|
|
|
||
|
|
## 接口
|
||
|
|
|
||
|
|
- SaaS 家庭端:现有 `GET /api/v1/web/login/session`、`POST /api/v1/web/login/sms/send`、`POST /api/v1/web/login/sms/verify`,网页界面无需改动。
|
||
|
|
- SaaS 管理端:现有 `/api/v1/web/operator/login/...` 对应接口,只有已预先绑定手机号的管理员能登录,不会通过短信自动创建管理员。
|
||
|
|
- 小程序:先 `POST /api/v1/mini/login/session` 取得 `customer.` 或 `operator.` 登录令牌;后续请求带 `Authorization: MiniLogin <login_token>` 与 `X-Request-ID: <UUID v4>`。调用 `POST /api/v1/mini/login/captcha` 获取图片验证码,再调用 `POST /api/v1/mini/login/sms/send`(请求体与网页 `SMSSendInput` 相同,现有登录页发送 `purpose=LOGIN`,服务端自动选择注册或登录模板),最后调用 `POST /api/v1/mini/login/sms/verify`,成功后获得 `Mini <access_token>`。无需浏览器 Cookie。响应中的 `sms_enabled` 可用于隐藏不可用的短信入口。
|
||
|
|
|
||
|
|
微信小程序页面源码位于独立的 `voicelink` 项目,登录页已接入手机号、图片验证码、短信验证码及 60 秒重发交互。已有微信授权/密码登录保持不变。小程序与本服务端需要分别构建和发布。
|
||
|
|
|
||
|
|
## 上线前验证
|
||
|
|
|
||
|
|
配置审核通过的签名/模板及密钥后,在测试手机号上实际发送一条,确认腾讯云控制台的发送记录、手机收到的内容、网页和小程序验证成功、错误验证码与重复验证失败,再逐步开启正式流量。不要用固定验证码或把验证码记录到日志。线上部署前应单独检查 Compose 最终环境变量,并避免把密钥内容打印到终端。
|