5.5 KiB
5.5 KiB
短信服务架构说明
设计理念
短信服务采用通用化、可扩展的设计:
- ✅ 配置保持通用,不绑定特定服务商
- ✅ 支持多种短信服务商切换
- ✅ 易于扩展新的服务商
- ✅ 统一的对外接口
架构设计
1. 配置层(通用化)
sms:
enabled: false # 是否启用
provider: aliyun # 服务商选择
access-key-id: xxx # 通用配置
access-key-secret: xxx
sign-name: xxx
template-code: xxx
region-id: xxx
设计优势:
- 配置不带服务商前缀,保持通用性
- 通过
provider灵活切换服务商 - 未来增加服务商无需修改配置结构
2. 工具类层(SmsUtils)
@Component
public class SmsUtils {
// 通用配置
@Value("${sms.provider:aliyun}")
private String provider;
// 对外统一接口
public boolean sendVerificationCode(String phone, String code) {
switch (provider) {
case "aliyun":
return sendByAliyun(phone, code);
case "tencent":
return sendByTencent(phone, code);
default:
return false;
}
}
// 各服务商的私有实现
private boolean sendByAliyun(String phone, String code) { ... }
private boolean sendByTencent(String phone, String code) { ... }
}
设计优势:
- 对外统一接口:
sendVerificationCode() - 各服务商只是内部的私有方法
- 调用方无需关心使用哪个服务商
- 新增服务商只需添加一个私有方法
3. 调用层(AuthController)
@Autowired
private SmsUtils smsUtils;
public ResultDomain<Boolean> sendSmsCode(...) {
// 直接调用统一接口,无需关心服务商
boolean success = smsUtils.sendVerificationCode(phone, code);
...
}
支持的服务商
当前已实现
- ✅ 阿里云(dysmsapi20170525)
待实现
- ⏳ 腾讯云(预留接口)
- ⏳ 华为云(预留接口)
如何添加新服务商
步骤1:添加Maven依赖
在 common-util/pom.xml 中添加对应SDK:
<!-- 例如:腾讯云短信 -->
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java</artifactId>
<version>3.x.x</version>
</dependency>
步骤2:实现私有方法
在 SmsUtils.java 中添加私有实现方法:
/**
* 使用腾讯云发送短信验证码
*/
private boolean sendByTencent(String phone, String code) {
try {
// 腾讯云SDK调用逻辑
...
return true;
} catch (Exception e) {
logger.error("腾讯云短信发送失败", e);
return false;
}
}
步骤3:添加到分发逻辑
在 sendVerificationCode() 方法中添加case:
switch (provider.toLowerCase()) {
case "aliyun":
return sendByAliyun(phone, code);
case "tencent":
return sendByTencent(phone, code); // 新增
default:
logger.error("未知的短信服务商: {}", provider);
return false;
}
步骤4:配置切换
修改 application.yml:
sms:
provider: tencent # 切换到腾讯云
完成!无需修改调用方代码。
开发模式
模拟模式(推荐用于开发)
sms:
enabled: false # 关闭真实发送
特点:
- 不会实际发送短信
- 验证码输出到日志
- 不产生任何费用
- 便于本地调试
真实发送模式
sms:
enabled: true
provider: aliyun
access-key-id: xxx
access-key-secret: xxx
最佳实践
1. 环境隔离
开发环境:
sms:
enabled: false # 模拟模式
生产环境:
sms:
enabled: true
provider: aliyun
access-key-id: ${SMS_ACCESS_KEY_ID} # 从环境变量读取
access-key-secret: ${SMS_ACCESS_KEY_SECRET}
2. 安全性
- ❌ 不要将 AccessKey 写在代码中
- ❌ 不要将 AccessKey 提交到 Git
- ✅ 使用环境变量或配置中心
- ✅ 使用 RAM 子账号而非主账号
- ✅ 定期更换密钥
3. 可靠性
// 系统已实现:
- 60秒发送频率限制(防刷)
- 10分钟验证码有效期
- Redis存储验证码
- 手机号格式验证
// 建议增加:
- 图形验证码前置
- IP限流
- 黑名单机制
- 发送失败重试
4. 监控告警
建议监控指标:
- 短信发送成功率
- 短信发送量(防异常消耗)
- 验证码验证成功率
- 单个手机号发送频率
优势总结
对比旧方案
旧方案(绑定服务商):
aliyun:
sms:
enabled: true
- ❌ 配置绑定服务商
- ❌ 切换服务商需要大量修改
- ❌ 扩展性差
新方案(通用化):
sms:
provider: aliyun
enabled: true
- ✅ 配置保持通用
- ✅ 切换服务商只需修改
provider - ✅ 扩展性强,易于维护
符合设计原则
- 开闭原则:对扩展开放,对修改关闭
- 单一职责:每个服务商实现独立
- 依赖倒置:调用方依赖抽象接口,不依赖具体实现
- 里氏替换:各服务商实现可以互相替换
总结
这个架构设计的核心理念是:
- 配置通用化:不绑定特定服务商
- 实现私有化:服务商只是一个方法
- 接口统一化:对外提供统一接口
- 扩展简单化:新增服务商仅需3步
这样的设计既满足当前需求,又具备良好的扩展性,是一个优雅、实用、易维护的架构方案。