Files
happy-life-star/AUTH_REGISTER_OPTIMIZATION.md
T
2025-10-13 10:43:08 +08:00

11 KiB
Raw Blame History

注册接口优化总结

🎯 优化目标

简化用户注册流程,仅需要手机号、密码和短信验证码即可完成注册。

完成的优化

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. 生产环境优化

需要修改的地方:

  1. 移除响应中的验证码

    return SmsCodeResponse.builder()
            // .code(code)  // 生产环境删除此行
            .expiresIn((long) SMS_CODE_EXPIRE_MINUTES * 60)
            .message("验证码已发送,有效期" + SMS_CODE_EXPIRE_MINUTES + "分钟")
            .build();
    
  2. 添加发送频率限制

    • 同一手机号60秒内只能发送一次
    • 同一IP每天最多发送10次
  3. 添加验证码尝试次数限制

    • 同一手机号最多尝试5次
    • 超过次数后需要重新获取验证码

验证清单

  • 编译成功,无错误
  • RegisterRequest简化为3个字段
  • 新增SmsCodeResponse响应类
  • 新增获取短信验证码接口
  • 实现短信验证码发送逻辑
  • 实现短信验证码校验逻辑
  • 实现随机用户名生成
  • 优化注册接口逻辑
  • 添加Swagger API文档注解
  • 添加详细的日志记录

🎉 总结

成功优化了注册接口,实现了以下目标:

  1. 简化注册流程 - 仅需手机号、密码和短信验证码
  2. 自动生成用户名 - 开心 + 6位随机大小写字母和数字
  3. 短信验证码机制 - 默认123456,预留真实短信服务接入点
  4. 完整的校验逻辑 - 手机号格式、唯一性、验证码有效性
  5. 良好的代码质量 - 清晰的注释、完善的日志、标准的异常处理

现在用户可以通过简单的3步完成注册:

  1. 输入手机号获取验证码
  2. 输入密码和验证码
  3. 自动生成用户名并完成注册

注册成功后自动登录,返回访问令牌和用户信息!