登录注册、手机号、邮箱

This commit is contained in:
2025-11-03 13:37:55 +08:00
parent 16754b527e
commit 35aee59178
26 changed files with 4292 additions and 163 deletions

View File

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