11 KiB
11 KiB
注册接口优化总结
🎯 优化目标
简化用户注册流程,仅需要手机号、密码和短信验证码即可完成注册。
✅ 完成的优化
1. 简化RegisterRequest
文件: backend-single/src/main/java/com/emotion/dto/request/RegisterRequest.java
修改前:需要账号、密码、确认密码、用户名、昵称、邮箱、手机号、图形验证码等多个字段
修改后:仅需3个字段
@Data
@EqualsAndHashCode(callSuper = true)
public class RegisterRequest extends BaseRequest {
/**
* 手机号(作为账号)
*/
@NotBlank(message = "手机号不能为空")
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
private String phone;
/**
* 密码
*/
@NotBlank(message = "密码不能为空")
@Size(min = 6, max = 20, message = "密码长度必须在6-20个字符之间")
private String password;
/**
* 短信验证码
*/
@NotBlank(message = "验证码不能为空")
@Size(min = 6, max = 6, message = "验证码必须为6位")
private String smsCode;
}
2. 新增SmsCodeResponse
文件: backend-single/src/main/java/com/emotion/dto/response/SmsCodeResponse.java
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SmsCodeResponse {
/**
* 验证码(开发环境返回,生产环境不返回)
*/
private String code;
/**
* 过期时间(秒)
*/
private Long expiresIn;
/**
* 提示信息
*/
private String message;
}
3. 新增获取短信验证码接口
文件: backend-single/src/main/java/com/emotion/controller/AuthController.java
/**
* 获取短信验证码(用于注册)
*/
@GetMapping("/sms-code")
@Operation(summary = "获取短信验证码", description = "用于注册时的短信验证码")
public Result<SmsCodeResponse> getSmsCode(
@Parameter(description = "手机号", required = true)
@RequestParam String phone) {
SmsCodeResponse response = authService.sendSmsCode(phone);
return Result.success("验证码已发送", response);
}
接口地址: GET /api/auth/sms-code?phone=13800138000
响应示例:
{
"code": 200,
"message": "验证码已发送",
"data": {
"code": "123456",
"expiresIn": 300,
"message": "验证码已发送,有效期5分钟"
}
}
4. 优化注册接口逻辑
文件: backend-single/src/main/java/com/emotion/service/impl/AuthServiceImpl.java
4.1 新增常量定义
private static final String SMS_CODE_PREFIX = "sms_code:";
private static final int SMS_CODE_EXPIRE_MINUTES = 5;
private static final String DEFAULT_SMS_CODE = "123456";
4.2 简化注册逻辑
@Override
public AuthResponse register(RegisterRequest request) {
// 1. 验证短信验证码
if (!validateSmsCode(request.getPhone(), request.getSmsCode())) {
throw new CaptchaException("验证码错误或已过期");
}
// 2. 检查手机号是否已存在
if (userService.getByPhone(request.getPhone()) != null) {
throw new BusinessException("手机号已被注册");
}
// 3. 生成随机用户名:开心 + 6位随机大小写字母和数字
String username = generateRandomUsername();
// 4. 使用手机号作为账号
String account = request.getPhone();
// 5. 创建用户
User user = userService.createUser(
account,
username,
request.getPassword(),
null, // 邮箱为空
request.getPhone()
);
// 6. 生成令牌并返回
// ...
}
4.3 实现短信验证码发送
@Override
public SmsCodeResponse sendSmsCode(String phone) {
// 验证手机号格式
if (!StringUtils.hasText(phone) || !phone.matches("^1[3-9]\\d{9}$")) {
throw new BusinessException("手机号格式不正确");
}
// 检查手机号是否已注册
if (existsByPhone(phone)) {
throw new BusinessException("该手机号已被注册");
}
// TODO: 接入真实的短信服务商(阿里云、腾讯云等)
// 目前使用固定验证码 123456
String code = DEFAULT_SMS_CODE;
// 将验证码存储到Redis,有效期5分钟
String key = SMS_CODE_PREFIX + phone;
redisTemplate.opsForValue().set(key, code, SMS_CODE_EXPIRE_MINUTES, TimeUnit.MINUTES);
log.info("发送短信验证码: phone={}, code={}", phone, code);
// 构建响应
return SmsCodeResponse.builder()
.code(code) // 开发环境返回验证码,生产环境应该删除此行
.expiresIn((long) SMS_CODE_EXPIRE_MINUTES * 60)
.message("验证码已发送,有效期" + SMS_CODE_EXPIRE_MINUTES + "分钟")
.build();
}
4.4 实现短信验证码校验
@Override
public boolean validateSmsCode(String phone, String code) {
if (!StringUtils.hasText(phone) || !StringUtils.hasText(code)) {
return false;
}
String key = SMS_CODE_PREFIX + phone;
String storedCode = (String) redisTemplate.opsForValue().get(key);
if (storedCode == null) {
log.warn("短信验证码不存在或已过期: phone={}", phone);
return false;
}
boolean isValid = storedCode.equals(code);
// 验证成功后删除验证码(一次性使用)
if (isValid) {
redisTemplate.delete(key);
log.info("短信验证码验证成功: phone={}", phone);
} else {
log.warn("短信验证码错误: phone={}, expected={}, actual={}", phone, storedCode, code);
}
return isValid;
}
4.5 实现随机用户名生成
/**
* 生成随机用户名
* 格式:开心 + 6位随机大小写字母和数字
*
* @return 随机用户名
*/
private String generateRandomUsername() {
String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
Random random = new Random();
StringBuilder sb = new StringBuilder("开心");
for (int i = 0; i < 6; i++) {
int index = random.nextInt(chars.length());
sb.append(chars.charAt(index));
}
return sb.toString();
}
用户名示例:
- 开心A3bC9z
- 开心X7yK2m
- 开心P1qW5n
5. 更新AuthService接口
文件: backend-single/src/main/java/com/emotion/service/AuthService.java
新增方法定义:
/**
* 发送短信验证码
*
* @param phone 手机号
* @return 短信验证码响应
*/
SmsCodeResponse sendSmsCode(String phone);
/**
* 验证短信验证码
*
* @param phone 手机号
* @param code 验证码
* @return 是否验证成功
*/
boolean validateSmsCode(String phone, String code);
📊 优化对比
| 项目 | 优化前 | 优化后 |
|---|---|---|
| 必填字段 | 账号、密码、确认密码、验证码、验证码key | 手机号、密码、短信验证码 |
| 验证码类型 | 图形验证码 | 短信验证码 |
| 用户名生成 | 手动输入或使用账号 | 自动生成(开心+6位随机) |
| 账号 | 手动输入 | 自动使用手机号 |
| 邮箱 | 可选输入 | 不需要 |
| 昵称 | 可选输入 | 自动使用用户名 |
🔧 核心特性
1. 简化注册流程
- ✅ 仅需3个字段:手机号、密码、短信验证码
- ✅ 自动生成用户名:开心 + 6位随机字符
- ✅ 手机号作为账号
- ✅ 移除了确认密码、邮箱、昵称等非必要字段
2. 短信验证码机制
- ✅ 默认验证码:123456(开发环境)
- ✅ 有效期:5分钟
- ✅ 一次性使用:验证成功后自动删除
- ✅ Redis存储:支持分布式部署
- ✅ TODO标记:预留真实短信服务接入点
3. 安全性保障
- ✅ 手机号格式验证
- ✅ 手机号唯一性检查
- ✅ 验证码过期检查
- ✅ 验证码一次性使用
- ✅ 密码加密存储
4. 用户体验优化
- ✅ 注册流程简单快捷
- ✅ 自动生成友好的用户名
- ✅ 清晰的错误提示
- ✅ 完整的API文档(Swagger)
🚀 使用示例
1. 获取短信验证码
请求:
curl -X GET "http://localhost:19089/api/auth/sms-code?phone=13800138000"
响应:
{
"code": 200,
"message": "验证码已发送",
"data": {
"code": "123456",
"expiresIn": 300,
"message": "验证码已发送,有效期5分钟"
}
}
2. 用户注册
请求:
curl -X POST "http://localhost:19089/api/auth/register" \
-H "Content-Type: application/json" \
-d '{
"phone": "13800138000",
"password": "password123",
"smsCode": "123456"
}'
响应:
{
"code": 200,
"message": "注册成功",
"data": {
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expiresIn": 86400,
"userInfo": {
"id": "1844234567890123456",
"account": "13800138000",
"username": "开心A3bC9z",
"nickname": "开心A3bC9z",
"phone": "13800138000",
"memberLevel": "free",
"status": 1
},
"loginTime": "2025-10-06 21:49:33"
}
}
📝 TODO事项
1. 接入真实短信服务
位置: AuthServiceImpl.sendSmsCode() 方法
当前代码:
// TODO: 接入真实的短信服务商(阿里云、腾讯云等)
// 目前使用固定验证码 123456
String code = DEFAULT_SMS_CODE;
后续改进:
// 生成随机6位数字验证码
String code = String.format("%06d", new Random().nextInt(1000000));
// 调用短信服务商API发送验证码
// 示例:阿里云短信服务
// smsService.sendSms(phone, code);
2. 生产环境优化
需要修改的地方:
-
移除响应中的验证码:
return SmsCodeResponse.builder() // .code(code) // 生产环境删除此行 .expiresIn((long) SMS_CODE_EXPIRE_MINUTES * 60) .message("验证码已发送,有效期" + SMS_CODE_EXPIRE_MINUTES + "分钟") .build(); -
添加发送频率限制:
- 同一手机号60秒内只能发送一次
- 同一IP每天最多发送10次
-
添加验证码尝试次数限制:
- 同一手机号最多尝试5次
- 超过次数后需要重新获取验证码
✅ 验证清单
- 编译成功,无错误
- RegisterRequest简化为3个字段
- 新增SmsCodeResponse响应类
- 新增获取短信验证码接口
- 实现短信验证码发送逻辑
- 实现短信验证码校验逻辑
- 实现随机用户名生成
- 优化注册接口逻辑
- 添加Swagger API文档注解
- 添加详细的日志记录
🎉 总结
成功优化了注册接口,实现了以下目标:
- ✅ 简化注册流程 - 仅需手机号、密码和短信验证码
- ✅ 自动生成用户名 - 开心 + 6位随机大小写字母和数字
- ✅ 短信验证码机制 - 默认123456,预留真实短信服务接入点
- ✅ 完整的校验逻辑 - 手机号格式、唯一性、验证码有效性
- ✅ 良好的代码质量 - 清晰的注释、完善的日志、标准的异常处理
现在用户可以通过简单的3步完成注册:
- 输入手机号获取验证码
- 输入密码和验证码
- 自动生成用户名并完成注册
注册成功后自动登录,返回访问令牌和用户信息!