diff --git a/docs/superpowers/specs/2026-05-22-sms-register-design.md b/docs/superpowers/specs/2026-05-22-sms-register-design.md
index 70bad43..7176c3f 100644
--- a/docs/superpowers/specs/2026-05-22-sms-register-design.md
+++ b/docs/superpowers/specs/2026-05-22-sms-register-design.md
@@ -126,14 +126,18 @@ register.vue setNickname.vue
```
**优点:**
-- 阿里云 credentials 配置原本就在 gateway(OSS 用的是同一套),直接复用
+- 网关已有阿里云 AccessKey 配置,可直接用于 SMS(短信使用直接 AccessKey,非 STS)
- 前端请求在网关层就能触发短信,不用穿透到后端服务
- 网关是单点,处理短信很方便
**缺点:**
- 短信发送成功后的后续注册流程还在 userService,逻辑割裂
-- 网关承担了越来越多的职责(路由、认证、OSS上传、现在又加短信),越来越重
-- 如果 SMS 认证配置要从 gateway 复用,需要确保 userService 能访问到同一份配置,增加了部署耦合
+- 网关承担了越来越多的职责(路由、认证、OSS上传签名、现在又加短信),越来越重
+- 网关当前 OSS 相关接口:
+ - `GET /oss/signature` - 获取 OSS 上传签名
+ - `GET /oss/presigned-url` - 获取 OSS 预签名URL(读取用)
+ - `GET /oss/batch-presigned-urls` - 批量获取 OSS 预签名URL
+- SMS 和 OSS 认证方式不同(SMS 用直接 AccessKey,OSS 用 STS Role ARN),实际上并不能完全复用同一套配置
**适用场景**:适合短信作为独立操作、不属于用户注册主流程的场景。
@@ -155,9 +159,9 @@ register.vue setNickname.vue
| 项目 | 选择 |
|------|------|
-| 短信 SDK | `github.com/alibabacloud-go/dysmsapi-20180501/v2`(阿里官方 V2 Go SDK) |
+| 短信 SDK | `github.com/alibabacloud-go/dysmsapi-20180501/v2/client`(阿里官方 V2 Go SDK) |
| 环境要求 | Go 1.10.x 或更高 |
-| 安装方式 | `go get github.com/alibabacloud-go/dysmsapi-20180501/v2` |
+| 安装方式 | `go get github.com/alibabacloud-go/dysmsapi-20180501/v2/client` |
| 依赖包 | 还需 `github.com/alibabacloud-go/darabonba-openapi/v2/client` |
| 认证方式 | 阿里云默认凭据链(AccessKey 等)自动查找 |
| API Endpoint | `dysmsapi.aliyuncs.com` |
@@ -216,13 +220,70 @@ Value (Hash):
TTL: 60 秒
```
-### 7.3 防暴力破解策略
+### 7.3 防暴力破解与限流策略
-- **失败计数**:每次验证失败递增 attempts 字段,≥ 3 次后删除 Key,要求用户重新获取
-- **发送频率限制**:每小时最多发送 10 次,超限返回 429
- - 使用独立 Key `sms:limit:register:{mobile}` 计数(String 类型,TTL=3600 秒)
-- **IP 维度限流**(可选):每 IP 每小时最多请求 30 次
- - 使用独立 Key `sms:limit:ip:{ip}` 计数(String 类型,TTL=3600 秒)
+#### 限制规则总览
+
+| 限制维度 | 限制规则 | TTL | 触发动作 |
+|---------|---------|-----|---------|
+| 同一手机号(发送) | 60 秒内不能重复发送 | 60s | 返回 429 |
+| 同一手机号(发送) | 每小时最多 10 次 | 3600s | 返回 429 |
+| 同一手机号(验证) | 最多失败 3 次 | 60s | 删除验证码,要求重新获取 |
+| 同一 IP(发送) | 每小时最多 30 次 | 3600s | 返回 429 |
+| 同一 IP(验证) | 每分钟最多 10 次 | 60s | 返回 429 |
+| 验证码有效期 | 60 秒 | 60s | 过期自动失效 |
+
+#### Redis Key 设计
+
+```
+# 验证码存储(Hash)
+sms:register:{mobile}
+ code: "123456"
+ created_at: "1700000000"
+ attempts: "0"
+TTL: 60秒
+
+# 手机号发送频率(String,每小时清一次)
+sms:limit:mobile:register:{mobile}
+ value: "1" (计数器,每次发送 INCR)
+TTL: 3600秒
+
+# IP 发送频率(String,每小时清一次)
+sms:limit:ip:send:{ip}
+ value: "1"
+TTL: 3600秒
+
+# IP 验证频率(String,每分钟清一次)
+sms:limit:ip:verify:{ip}
+ value: "1"
+TTL: 60秒
+```
+
+#### 防御措施详情
+
+**1. 发送频率限制**
+- 60 秒内同一手机号只能发送 1 次(防止轰炸)
+- 每小时同一手机号最多发送 10 次(结合套餐包成本控制)
+- 每小时同一 IP 最多发送 30 次(防止 IP 轮询攻击)
+
+**2. 验证失败限制**
+- 验证码错误后递增 attempts 计数器
+- 失败 3 次后强制删除验证码,要求用户重新获取
+- 60 秒内同一 IP 最多发起 10 次验证请求
+
+**3. IP 黑名单机制**
+- 触发限流时记录来源 IP
+- 1 小时内触发 3 次限流的 IP,临时拉黑 30 分钟
+- 黑名单 Key: `sms:blacklist:ip:{ip}`,TTL=1800 秒
+
+**4. 验证码安全**
+- 验证码为 6 位纯数字,共 100 万种组合
+- 有效期 60 秒,暴力破解窗口极小
+- 验证成功后立即删除,防止重放
+
+**5. 异常检测**
+- 同一手机号在 5 分钟内连续失败 5 次,触发告警(可考虑临时冻结)
+- 同一 IP 在 5 分钟内请求超过 50 次,触发告警
### 7.4 验证后处理
@@ -243,10 +304,13 @@ POST /api/v1/auth/send-code
Content-Type: application/json
{
- "mobile": "13800138000"
+ "mobile": "13800138000",
+ "scene": "register"
}
```
+`scene` 可选值:`register`(注册)、`password`(找回密码)。
+
**响应**
```json
{
@@ -267,7 +331,8 @@ Content-Type: application/json
{
"mobile": "13800138000",
- "code": "123456"
+ "code": "123456",
+ "scene": "register"
}
```
@@ -325,7 +390,9 @@ Content-Type: application/json
| 验证码已使用 | 400 | 提示"验证码已使用,请重新获取" |
| 发送频率超限(60秒内重复发送) | 429 | 提示"发送过于频繁,请稍后再试" |
| 每小时发送次数超限(>10次) | 429 | 提示"当前手机号发送次数超限,请稍后再试" |
-| IP 请求频率超限 | 429 | 提示"请求过于频繁,请稍后再试" |
+| IP 发送频率超限(>30次/小时) | 429 | 提示"请求过于频繁,请稍后再试" |
+| IP 验证频率超限(>10次/分钟) | 429 | 提示"请求过于频繁,请稍后再试" |
+| IP 被临时拉黑 | 403 | 提示"暂时无法操作,请稍后再试" |
---
@@ -353,6 +420,8 @@ SMS_REGION=cn-hangzhou
2. **verify_token 安全**:token 有效期 5 分钟,只能使用一次,验证后立即删除
3. **防暴力破解**:验证失败 3 次后强制删除验证码,要求用户重新获取
4. **限流保护**:从手机号和 IP 两个维度限制请求频率
+5. **IP 黑名单**:1 小时内触发 3 次限流的 IP,临时拉黑 30 分钟
+6. **异常告警**:同一手机号 5 分钟内连续失败 5 次,或同一 IP 5 分钟内请求超 50 次,触发告警
---
@@ -371,24 +440,202 @@ SMS_REGION=cn-hangzhou
> 💡 **推荐**:5,000 条或 15,000 条套餐性价比最高,适合中等规模业务使用。
-### 12.2 短信模板类型
+### 12.2 短信模板规范
+
+#### 模板类型
| 模板类型 | 说明 | 审核时间 |
|----------|------|----------|
-| 验证码模板 | 仅含变量(如 ${code}),用于发送随机验证码 | 通常 2 小时内 |
+| **验证码模板** | 仅含变量(如 ${code}),用于发送随机验证码 | 通常 2 小时内 |
| 通知模板 | 含固定文本 + 少量变量 | 通常 2 小时内 |
| 推广模板 | 营销类内容,审核更严格 | 通常 4 小时以上 |
-**验证码模板示例:**
-```
-您的注册验证码是${code},5分钟内有效。如非本人操作,请忽略此短信。
-```
+#### 内容规范
-### 12.3 签名
+**必须包含:**
+- 必须包含"**验证码、注册码、校验码、动态码**"之一
+- 必须体现"**使用平台、用途、失效时间**"之一
-- 签名是短信发送者的标识,位于短信内容开头
-- 一个账号可创建多个签名,需审核通过后才能使用
-- 签名名称示例:`TopFans`、`TOPFANS官方`
+**禁止包含:**
+- 不能含有通知、营销、广告词语、退订方式
+- 结尾不能包含"拒收请回复R"
+- **不能含任何联系方式**:手机/固话/QQ/微信/抖音/钉钉/旺旺/闲鱼/小红书/邮箱等
+- 用途为"他用"的签名不支持申请金融相关模板
+
+#### 格式规范
+
+| 项目 | 规范 |
+|------|------|
+| **模板长度** | 1~500 个字符(含变量) |
+| **支持字符** | 中文、英文、数字、符号 |
+| **不支持** | 繁体字、特殊符号(如 `#`、`『』、『「」、「」、〖〗`、`m²`、`•`、`①`、`★`、`※`、`→` 等) |
+| **禁止** | 错别字、变体字、异体字、各类干扰符号 |
+| **模板内容中禁用** | `【】`符号(任意位置),首尾禁用`[ ]` |
+
+#### 变量规范
+
+| 变量类型 | 变量名示例 | 变量规范 |
+|---------|-----------|---------|
+| **单变量(仅数字)** | `${code}`、`${time}` | 长度限制 4~6 位 |
+| **单变量(数字+字母)** | `${code}` | 长度限制 4~6 位 |
+| **双变量** | `${code}`、`${time}` | 仅支持通过控制台"常用模板推荐"申请,不支持自定义 |
+
+**变量格式要求:**
+- 变量格式为 `${变量名}`,其中 `$` 符号在 `{ }` 外面
+- 变量名首字母必须为英文字母
+- 变量名只能由字母、数字和下划线组成
+- **变量名不能为**:email、mobile、id、nick、site、ip 等
+
+#### 验证码模板示例
+
+| 应用场景 | 模板内容 |
+|---------|---------|
+| 登录 | 您的验证码`${code}`,该验证码5分钟内有效,请勿泄露给他人! |
+| 登录 | 验证码为:`${code}`,您正在登录,若非本人操作,请勿泄露。 |
+| 注册 | 您正在申请手机注册,验证码为:`${code}`,5分钟内有效! |
+| 注册 | 尊敬的用户,您的注册会员动态密码为:`${code}`,请勿泄露于他人! |
+| 注册 | 您的注册码:`${code}`,如非本人操作,请忽略本短信! |
+| 重置密码 | 您的动态码为:`${code}`,您正在进行密码重置操作,如非本人操作,请忽略本短信! |
+
+#### 审核时长
+
+- 预计 **2 个小时** 内审核完成
+- 工作时间:周一至周日 9:00~21:00(法定节假日顺延)
+
+#### 常见审核失败原因
+
+| 类别 | 驳回原因 | 处理建议 |
+|------|---------|---------|
+| 内容模糊 | 模板没有体现业务内容,含义不明 | 使用实际业务内容 |
+| 场景不详 | 模板使用场景不详 | 在场景说明中填写业务场景或线上链接 |
+| 含退订方式 | 验证码模板包含退订方式 | 删除退订方式后重新提交 |
+| 多变量 | 验证码模板包含多变量 | 去掉多余变量,仅支持单变量或双变量 |
+| 关键词不全 | 缺少"验证码/注册码/校验码/动态码"之一 | 添加验证码关键词之一 |
+| 变量格式错误 | 变量格式不符合规范 | 变量格式为 `${code}`,首字母必须为英文字母 |
+| 模板类型错误 | 模板类型选择与实际需求不匹配 | 根据场景选择验证码/通知/推广模板 |
+
+##### 模板审核详细失败原因
+
+| 类别 | 驳回原因 | 处理建议 |
+|------|---------|---------|
+| 内容模糊 | 模板没有体现业务内容,含义不明 | 使用实际业务内容进行测试 |
+| 内容模糊 | 模板使用场景不详 | 填写业务场景或线上链接,提供测试账号密码 |
+| 内容模糊 | 应用市场中未核实到App/公众号/小程序 | 填写正确链接,若产品未上线暂不支持申请 |
+| 内容模糊 | 业务内容不明确(如"加微信送礼") | 不支持加群内容,删除后重新提交 |
+| 格式问题 | 推广短信模板包含变量 | 将变量内容体现在模板文案中 |
+| 格式问题 | 推广短信没包含退订方式 | 加上 `拒收请回复R` |
+| 格式问题 | 验证码/通知模板包含退订方式 | 删除退订方式后重新提交 |
+| 格式问题 | 验证码模板包含多变量 | 去掉多余变量,仅支持单变量或双变量 |
+| 格式问题 | 验证码模板包含无关内容 | 删除与验证码无关的内容 |
+| 格式问题 | 验证码关键词不全 | 必须含验证码/注册码/校验码/动态码之一 |
+| 格式问题 | 通知模板包含推广内容 | 删除推广部分或申请推广模板 |
+| 格式问题 | 含错别字/繁体字/特殊符号/中括号 | 修改为正确内容,【】符号不能在模板内容中使用 |
+| 内容问题 | 内容涉及金融/交友/宗教/游戏 | 交友/游戏仅支持验证码模板;他用签名不支持金融相关 |
+| 内容问题 | 内容涉及第三方 | 需提供第三方企业证件和授权委托书 |
+| 内容问题 | 内容涉及营销信息 | 提供隐私协议截图、会员管理系统截图,备注投诉对接人 |
+| 变量问题 | 变量内传入链接/IP地址/App等 | 变量外使用链接,固定链接用一级域名+变量格式 |
+| 变量问题 | 变量内容模糊 | 修改表达以清晰判断参数内容 |
+| 变量问题 | 变量格式错误 | 变量格式`${code}`,首字母必须为英文字母,不能为email/mobile/id/nick/site/ip |
+| 变量问题 | 变量属性选择错误 | 根据业务场景选择合适的变量属性 |
+| 链接问题 | 链接无ICP备案 | 提供已ICP备案的网址链接 |
+| 链接问题 | 短链+变量格式不符合规范 | 改为一级的域名或官网链接+变量组合 |
+| 链接问题 | 链接存在跳转 | 将原链接压缩成短链 |
+| 链接问题 | 链接无法访问 | 提供公网可访问的链接 |
+| SEO推广 | 涉及数据排名/关键字搜索/精准拓客引流 | 修改模板内容 |
+
+### 12.3 签名规范
+
+#### 什么是短信签名
+
+短信签名是短信发送方属性的一种标识,一条完整的短信由**短信签名**和**短信内容**组成。短信签名位于短信内容前的`【】`中,用于标识企业、产品或业务。
+
+**示例**:`【阿里云】您的验证码是123456` - 签名`阿里云`会自动补全`【】`
+
+#### 签名来源要求
+
+| 签名来源 | 说明 |
+|---------|------|
+| **企事业单位名**(推荐) | 企业名称的全称或简称,极大提升签名报备成功率 |
+| 已注册商标名 | 需在国家知识产权局商标局可查且注册主体一致 |
+
+> ⚠️ **不支持**:公众号、小程序、电商平台店铺名、已上线APP、测试/学习用途作为签名来源
+
+#### 签名内容规范
+
+| 项目 | 规范 |
+|------|------|
+| **签名内容** | 需能明确辨别发送方公司信息、产品或业务 |
+| **支持** | 企事业单位名、已注册商标名 |
+| **不支持** | 含义模糊的中性签名(如"客服通知"、"客户您好"、"温馨提示") |
+| **不支持** | 个人姓名 |
+| **不支持** | 含"测试"、"test"等字样的签名 |
+| **不支持** | 全英文签名、全数字签名、英文+数字组合 |
+| **不支持** | 特殊符号(含空格)、繁体字 |
+| **格式** | 申请时直接填写签名名称,无需添加【】等符号,系统会自动添加 |
+
+#### 签名长度限制
+
+- 长度:**2~12个字符**
+- 中文、英文、数字按1个字符计算
+
+#### 签名用途
+
+| 用途 | 说明 |
+|------|------|
+| **自用** | 资质对应的企业/个人信息与阿里云账号信息一致 |
+| **他用** | 需上传委托授权书,第三方仅支持企业及事业单位,不得为个人 |
+
+> ⚠️ **个人认证用户**:自用签名**无法通过**签名实名制报备,请申请他用资质或升级为企业认证账号
+
+#### 签名可申请次数
+
+| 账户类型 | 可申请次数 |
+|---------|-----------|
+| 个人认证用户 | 同阿里云账号一个自然日内支持申请 **1个** 签名 |
+| 企业认证用户 | **无数量限制** |
+
+#### 签名审核时长
+
+- 预计 **2个小时内** 审核完成
+- 工作时间:周一至周日 9:00~21:00(法定节假日顺延)
+- 运营商实名报备:**5-10个工作日**(可能更长)
+
+#### 签名状态异常原因
+
+| 状态 | 异常原因 |
+|------|---------|
+| 可用-异常 | 签名来源不合规、未关联资质、资质信息不全、实名制报备异常、长期未使用等 |
+| 不可用 | 审批未通过、被禁用、被冻结 |
+
+##### 签名审核详细失败原因
+
+| 类别 | 驳回原因 | 处理建议 |
+|------|---------|---------|
+| 内容模糊 | App/业务内容较少,无法核实业务场景 | 完善线上业务信息后再提交,不支持未上线产品 |
+| 内容模糊 | 签名过于宽泛,如"客服通知"、"客户您好" | 申请与已上线应用名称或企事业单位名称作为签名 |
+| 内容模糊 | 已提供信息,因无关联性被驳回 | 提供关联后台认证截图,备注关联性 |
+| 内容模糊 | 未核实到商标信息 | 在场景说明中提供商标注册号及完整商标名 |
+| 链接问题 | 链接无法访问 | 提供正确或公网可访问的链接 |
+| 链接问题 | 链接与签名无关联 | 申请企业名称作为签名 |
+| 链接问题 | 下载/内测链接无法核实业务主体 | 提供应用商城链接以便核实 |
+| 链接问题 | IP地址无法核实企业所属性 | 提供App或其他链接以便核实 |
+| 授权书 | 授权书未签字 | 在授权书右下角落款处让法定代表人或负责人签字 |
+| 授权书 | 授权书盖章错误 | 盖授权方(签名归属方)的企事业单位公章或合同章 |
+| 授权书 | 授权书无日期/有效期短/过期 | 填写完整有效期限,建议1~3年 |
+| 授权书 | 授权书内容变更 | 委托授权书经法务评估后出具,不支持变更内容 |
+| 授权书 | 被授权方/授权方/风险承担方填写错误 | 被授权方为账号认证主体名称,授权方和风险承担方为短信内容所属方 |
+| 资质材料 | 涉及政企业务但材料未提供完全 | 需提供授权委托书和组织机构代码证,场景说明备注固话 |
+| 资质材料 | 营业执照水印非平台使用 | 去除水印或改为"仅供云通信备案使用" |
+| 资质材料 | 证件无法查看 | 支持JPG、PNG、GIF、JPEG格式,每张不大于2MB |
+| 格式问题 | 签名名称包含"测试"字样 | 删除测试字样后重新提交 |
+| 格式问题 | 签名字数不符合要求 | 限制在2~12个字符内 |
+| 格式问题 | 签名带符号/繁体字/首字母拼写 | 国内短信不支持全英文、全数字、繁体字、特殊符号签名 |
+| 格式问题 | 签名是个人姓名 | 签名不能为个人姓名 |
+| 格式问题 | 签名是小程序或公众号 | 不支持申请 |
+
+#### 签名申请受限内容
+
+禁止包含:违法违规、色情、赌博、毒品、党政、博彩、彩票、暴力、恐吓、走私、成人用品、虚拟货币、烟草酒类、代开发票、代办证件、刷单、贷款催款、法律维权、股票私募、整容医美、宗教迷信、投资理财、房地产推广、游戏推广、交友推广、金融推广(含银行/保险/借贷)、招商加盟等内容的短信。
### 12.4 开通流程
@@ -412,7 +659,7 @@ SMS_REGION=cn-hangzhou
#### 依赖安装
```bash
-go get github.com/alibabacloud-go/dysmsapi-20170525/v4/client
+go get github.com/alibabacloud-go/dysmsapi-20180501/v2/client
go get github.com/alibabacloud-go/darabonba-openapi/v2/client
go get github.com/alibabacloud-go/tea/tea
go get github.com/alibabacloud-go/tea-utils/v2/service
@@ -446,7 +693,7 @@ setx ALIBABA_CLOUD_ACCESS_KEY_SECRET yourAccessKeySecret /M
import (
"os"
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
- dysmsapi20170525 "github.com/alibabacloud-go/dysmsapi-20170525/v4/client"
+ dysmsapi20170525 "github.com/alibabacloud-go/dysmsapi-20180501/v2/client"
"github.com/alibabacloud-go/tea/tea"
)
@@ -465,30 +712,32 @@ func CreateClient() (_result *dysmsapi20170525.Client, _err error) {
#### 发送短信(注册验证码场景)
+使用 `SendMessageWithTemplate` API 发送中国内地短信:
+
```go
import (
- dysmsapi20170525 "github.com/alibabacloud-go/dysmsapi-20170525/v4/client"
+ dysmsapi20170525 "github.com/alibabacloud-go/dysmsapi-20180501/v2/client"
util "github.com/alibabacloud-go/tea-utils/v2/service"
"github.com/alibabacloud-go/tea/tea"
)
-func SendVerificationCode() (_result *dysmsapi20170525.SendSmsResponse, _err error) {
+func SendVerificationCode() (_result *dysmsapi20170525.SendMessageWithTemplateResponse, _err error) {
client, _err := CreateClient()
if _err != nil {
return nil, _err
}
// 构造请求
- sendSmsRequest := &dysmsapi20170525.SendSmsRequest{
- PhoneNumbers: tea.String("13800138000"), // 手机号
- SignName: tea.String("TopFans"), // 签名
- TemplateCode: tea.String("SMS_xxxxxxx"), // 模板CODE
- TemplateParam: tea.String(`{"code":"123456"}`), // 模板变量
+ request := &dysmsapi20170525.SendMessageWithTemplateRequest{
+ ToNumber: tea.String("861503871XXXXX"), // 接收手机号,格式:国际区号+号码
+ FromNumber: tea.String("TopFans"), // 发送方标识(中国内地填签名)
+ TemplateCode: tea.String("SMS_xxxxxxx"), // 短信模板CODE
+ TemplateParam: tea.String(`{"code":"123456"}`), // 模板变量(JSON格式)
}
// 发送
runtime := &util.RuntimeOptions{}
- response, _err := client.SendSmsWithOptions(sendSmsRequest, runtime)
+ response, _err := client.SendMessageWithTemplateWithOptions(request, runtime)
if _err != nil {
return nil, _err
}
@@ -496,6 +745,33 @@ func SendVerificationCode() (_result *dysmsapi20170525.SendSmsResponse, _err err
}
```
+**请求参数说明**
+
+| 参数 | 类型 | 必填 | 说明 |
+|------|------|------|------|
+| ToNumber | string | 是 | 接收手机号,格式:`86` + 国内手机号,如 `861503871XXXXX` |
+| FromNumber | string | 是 | 发送方标识,中国内地填短信签名 |
+| TemplateCode | string | 是 | 短信模板 CODE |
+| TemplateParam | string | 否 | 模板变量 JSON,如 `{"code":"123456"}` |
+| SmsUpExtendCode | string | 否 | 上行短信扩展码 |
+
+**返回示例**
+
+```json
+{
+ "MessageId": "10080303003****",
+ "NumberDetail": {
+ "Carrier": "China Mobile",
+ "Country": "China",
+ "Region": "Nanjing, Jiangsu"
+ },
+ "ResponseCode": "OK",
+ "ResponseDescription": "The SMS Send Request was accepted",
+ "Segments": "1",
+ "To": "861503871XXXXX"
+}
+```
+
#### 返回码说明
| Code | 说明 |
@@ -537,13 +813,285 @@ fmt.Println(tea.StringValue(response.Body.Code))
| "Specified access key is not found" | AccessKey ID 错误或已删除 | 确认环境变量是否正确设置 |
| "dial tcp: lookup xxx: no such host" | Endpoint 配置错误 | 确认 Endpoint 为 `dysmsapi.aliyuncs.com` |
-### 12.6 相关文档
+### 12.6 开通步骤与资质要求
+
+#### 重要提示
+
+> ⚠️ **个人账号限制**:在当前的短信签名实名制要求下,个人账号的自用资质无法通过签名实名制报备。个人用户请使用短信认证产品或**升级为企业认证账号**。
+
+#### 开通步骤
+
+| 步骤 | 操作 | 说明 |
+|------|------|------|
+| ① 准备工作 | 注册阿里云账号 + 完成实名认证 + 开通短信服务 + 创建 AccessKey | API 调用必需 |
+| ② 申请资质 | 提交资质(企业/个人证明)→ 等待审核(预计 2 个工作日) | 国内短信必需 |
+| ③ 申请签名 | 提交签名 → 等待审核(预计 2 小时)→ 等待运营商报备(7-10 工作日) | 签名实名制报备 |
+| ④ 申请模板 | 提交模板 → 等待审核(预计 2 小时) | 验证码模板 |
+| ⑤ 发送短信 | 使用已审核通过的签名和模板发送 | 建议先少量测试 |
+| ⑥ 查询详情 | 查询发送状态、获取回执 | 可选 |
+| ⑦ 设置预警 | 配置联系人、验证码防盗刷、套餐包余量预警等 | 建议配置 |
+
+#### 资质要求
+
+##### 基本概念
+
+| 类型 | 说明 |
+|------|------|
+| **个人认证** | 阿里云账号认证类型为个人。**个人认证自用资质无法通过签名实名制报备**,请申请"他用资质"或升级为企业认证账号 |
+| **企业认证** | 阿里云账号认证类型为企业 |
+| **自用资质** | 资质企业/个人信息与阿里云账号已认证信息完全一致 |
+| **他用资质** | 资质企业/个人信息与阿里云账号已认证信息不一致,需提供委托授权书 |
+
+##### 资质材料清单
+
+| 材料类型 | 具体材料 | 说明 | 适用对象 |
+|---------|---------|------|---------|
+| **企业信息** | 加载统一社会信用代码的证照 | 社会信用代码证书、营业执照、事业单位法人证书等(选择一种) | 企业认证(自用/他用)、个人认证(他用) |
+| **法定代表人信息** | 姓名 + 身份证件 | 若证件中无法定代表人信息,需提供负责人或首席代表的身份证件 | 企业认证(自用/他用)、个人认证(他用) |
+| **管理员信息** | 管理员姓名 + 身份证件 + 手机号 | 管理员是管理短信业务的运营人员,可与企业法定代表人为同一人。**一人一企**:同一管理员只能关联一个企业资质,否则报备失败 | 企业认证(自用/他用)、个人认证(他用) |
+| **个人信息** | 个人身份证明 | 个人认证自用资质**无法通过**签名实名制报备 | 个人认证(自用) |
+
+##### 证件要求
+
+- 彩色原件无需盖章
+- 复印件/黑白照片需加盖**企业红章**并拍照上传
+- 证件标记建议修改为"仅供短信业务使用"或"仅供运营商报备使用"
+
+##### 资质审核时长
+
+- 预计 **2个工作日** 内完成
+- 工作时间:周一至周日 9:00~21:00(法定节假日顺延)
+
+##### 常见审核失败原因
+
+| 类别 | 问题 | 建议 |
+|------|------|------|
+| 企业信息 | 企业经营状态异常 | 向市场监管部门移除经营异常名录后再提交 |
+| 企业信息 | 证件标记非平台使用 | 修改为"仅供短信业务使用" |
+| 法定代表人 | 非中国国籍 | 护照、港澳居民来往内地通行证视为有效证件 |
+| 管理员 | 非中国国籍或港澳居民 | **仅支持身份证**,否则无法报备成功 |
+
+##### 资质审核详细失败原因
+
+| 类别 | 问题 | 原因/处理建议 |
+|------|------|---------------|
+| 企业信息 | 企业经营状态异常 | 企业已被列入经营异常名单。建议向市场监管部门移除经营异常名录 |
+| 企业信息 | 证件标记非平台使用 | 修改为"仅供短信业务使用"或"仅供运营商报备使用" |
+| 法定代表人 | 非中国国籍人士或港澳居民 | 护照、港澳居民来往内地通行证视为有效证件 |
+| 法定代表人 | 工商个体户没有公章 | 可提供法定代表人签名 |
+| 管理员 | 非中国国籍或港澳居民(无身份证) | **仅支持身份证**,否则无法报备成功 |
+
+##### 资质复用
+
+- **跨产品复用**:企业账号同时使用语音服务、号码隐私保护等产品时,可复用已审核通过的资质
+- **短信服务内复用**:可重复使用同一账号下已审核通过的资质
+
+#### 签名要求
+
+- 签名需要能明确辨别发送方
+- 建议使用企事业单位名称作为签名
+- 个人账号自用资质无法通过签名实名制报备
+- **未报备的签名会被运营商拦截发送**,返回 `PORT_NOT_REGISTERED` 错误
+
+#### 运营商报备时长
+
+- 平均 **5-7 个工作日**
+- 部分运营商可能需要 **7-10 个工作日**
+- 运营商未承诺此时效,实际可能更长
+- **建议**:提前申请资质和签名,预留足够时间完成实名报备后再正式使用
+
+#### 审核时间
+
+| 审核项 | 审核时间 | 工作时间 |
+|--------|---------|---------|
+| 资质审核 | 预计 2 个工作日 | 周一至周日 9:00~21:00,法定节假日顺延 |
+| 签名审核 | 预计 2 小时内 | 周一至周日 9:00~21:00 |
+| 模板审核 | 预计 2 小时内 | 周一至周日 9:00~21:00 |
+
+#### 建议配置项
+
+| 配置项 | 说明 |
+|--------|------|
+| 联系人设置 | 设置预警联系人,接收通知 |
+| 验证码防盗刷预警 | 建议开启,防止验证码被大量消耗 |
+| 套餐包余量预警 | 余额不足时通知 |
+| 发送频率预警 | 异常发送时通知 |
+
+---
+
+### 12.7 相关文档
- [阿里云短信服务帮助文档](https://help.aliyun.com/zh/sms)
- [快速入门(Go SDK)](https://help.aliyun.com/zh/sms/getting-started/get-started-with-sms)
- [SDK 示例](https://help.aliyun.com/zh/sms/sdk-demo/go)
- [SendSms API 文档](https://help.aliyun.com/zh/sms/developer-reference/sendsms)
- [Go SDK 源码仓库](https://github.com/alibabacloud-go/dysmsapi-20180501/)
+- [资质申请指南](https://help.aliyun.com/zh/sms/user-guide/apply-qualification)
+
+---
+
+### 12.8 短信使用记录表
+
+为方便后续资源核算,需记录每次短信发送情况。
+
+#### 方案一:PostgreSQL 表记录
+
+```sql
+CREATE TABLE sms_send_log (
+ id BIGSERIAL PRIMARY KEY,
+ mobile VARCHAR(20) NOT NULL COMMENT '手机号(脱敏存储)',
+ scene VARCHAR(20) NOT NULL DEFAULT 'register' COMMENT '使用场景:register/password',
+ template_code VARCHAR(50) NOT NULL COMMENT '短信模板CODE',
+ sign_name VARCHAR(50) NOT NULL COMMENT '短信签名',
+ message_id VARCHAR(64) DEFAULT '' COMMENT '阿里云返回的MessageId',
+ response_code VARCHAR(20) DEFAULT '' COMMENT '阿里云返回状态码',
+ response_description VARCHAR(255) DEFAULT '' COMMENT '阿里云返回描述',
+ status SMALLINT NOT NULL DEFAULT 1 COMMENT '发送状态:0=失败,1=成功',
+ send_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '发送时间',
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE INDEX idx_sms_send_log_mobile ON sms_send_log(mobile);
+CREATE INDEX idx_sms_send_log_scene ON sms_send_log(scene);
+CREATE INDEX idx_sms_send_log_send_time ON sms_send_log(send_time);
+```
+
+#### 方案二:Redis 记录(轻量级)
+
+使用 Redis 哈希记录发送统计,按月汇总:
+
+```
+Key: sms:stat:{year}:{month}
+Type: Hash
+Fields:
+ - total_count: 总发送条数
+ - success_count: 成功条数
+ - fail_count: 失败条数
+ - register_count: 注册场景条数
+ - password_count: 密码找回场景条数(未来扩展)
+```
+
+**推荐方案一(PostgreSQL)**,便于查询和导出做成本分析。
+
+#### 资源核算查询示例
+
+```sql
+-- 按月统计各场景短信发送量
+SELECT
+ TO_CHAR(send_time, 'YYYY-MM') AS month,
+ scene,
+ COUNT(*) AS total_count,
+ SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END) AS success_count,
+ SUM(CASE WHEN status = 0 THEN 1 ELSE 0 END) AS fail_count
+FROM sms_send_log
+GROUP BY TO_CHAR(send_time, 'YYYY-MM'), scene
+ORDER BY month DESC;
+
+-- 统计剩余套餐条数(结合阿里云控制台数据)
+-- 当前已消耗 = 注册验证成功 + 失败重试 等
+```
+
+---
+
+### 12.9 忘记密码/找回密码
+
+#### 功能概述
+
+用户可通过手机号验证码方式重置密码,与注册流程类似但更简洁:
+
+1. 用户输入手机号 → 发送验证码
+2. 输入验证码 → 验证通过
+3. 输入新密码 → 完成修改
+
+#### 前端页面变化
+
+新建 `frontend/pages/password/forget.vue`(找回密码页面):
+
+```
+forget.vue
+ │
+ ├── 输入手机号
+ ├── 点击"发送验证码" ──→ 发送验证码
+ ├── 输入验证码
+ ├── 点击"验证验证码" ──→ 验证通过
+ │ 返回 verify_token
+ ├── 输入新密码
+ └── 点击"确认修改" ──→ 修改密码 API
+ (mobile, verify_token, new_password)
+```
+
+#### 后端 API 变化
+
+| 接口 | 方法 | 说明 |
+|------|------|------|
+| `/api/v1/auth/send-code` | POST | 复用注册逻辑,scene=password |
+| `/api/v1/auth/verify-code` | POST | 复用注册逻辑,scene=password |
+| `/api/v1/auth/reset-password` | POST | 新接口,重置密码 |
+
+**重置密码接口:**
+
+```
+POST /api/v1/auth/reset-password
+Content-Type: application/json
+
+{
+ "mobile": "13800138000",
+ "verify_token": "vtf_abc123xyz789...",
+ "new_password": "xxx"
+}
+```
+
+**响应:**
+```json
+{
+ "code": 200,
+ "message": "密码修改成功",
+ "data": null
+}
+```
+
+**后端逻辑:**
+1. 根据 mobile 从 Redis 获取 `verify:password:{mobile}` 的值
+2. 与请求中的 verify_token 比对,不一致则拒绝
+3. 验证通过后删除该记录
+4. 使用新密码更新用户数据(需加密存储)
+5. 建议要求用户重新登录
+
+#### Redis Key 复用
+
+| 场景 | Key 格式 | 说明 |
+|------|----------|------|
+| 找回密码验证码 | `sms:password:{mobile}` | 验证码存储(TTL 60秒) |
+| 找回密码验证通过 | `verify:password:{mobile}` | 验证 token 存储(TTL 300秒) |
+
+限流规则与注册场景完全一致,共享 `sms:limit:*` 规则。
+
+#### 错误码
+
+| 场景 | 错误码 | 提示 |
+|------|--------|------|
+| 密码修改成功 | 200 | "密码修改成功" |
+| verify_token 无效/已过期 | 400 | "验证码已失效,请重新获取" |
+| 验证码错误 | 400 | "验证码错误" |
+| 同一手机号找回密码频率超限 | 429 | "操作过于频繁,请稍后再试" |
+
+#### 前端登录页入口
+
+在 `frontend/pages/login/login.vue` 添加"忘记密码"入口:
+
+```vue
+
+ 忘记密码
+
+```
+
+跳转到找回密码页面:
+```js
+uni.navigateTo({
+ url: '/pages/password/forget'
+});
+```
---
@@ -552,4 +1100,5 @@ fmt.Println(tea.StringValue(response.Body.Code))
- [ ] 阿里云短信签名和模板CODE(需在阿里云控制台创建)
- [ ] 验证码有效期(默认 60 秒是否合适)
- [ ] 每小时同一手机号发送次数上限(默认 10 次)
-- [ ] 验证失败次数上限(默认 3 次后强制重新获取)
\ No newline at end of file
+- [ ] 验证失败次数上限(默认 3 次后强制重新获取)
+- [ ] 找回密码页面是否需要单独创建,还是复用现有页面
\ No newline at end of file
diff --git a/frontend/pages/square/components/WaterfallGrid.vue b/frontend/pages/square/components/WaterfallGrid.vue
index c5aee91..8340e6f 100644
--- a/frontend/pages/square/components/WaterfallGrid.vue
+++ b/frontend/pages/square/components/WaterfallGrid.vue
@@ -1,52 +1,24 @@
-
-
-
+
+
+
-
+
-
+
-
+