代码优化
This commit is contained in:
@@ -0,0 +1,396 @@
|
||||
# 登录接口优化总结
|
||||
|
||||
## 🎯 优化目标
|
||||
|
||||
简化用户登录流程,使用手机号+短信验证码登录,若用户不存在则自动注册。
|
||||
|
||||
## ✅ 完成的优化
|
||||
|
||||
### 1. 简化LoginRequest
|
||||
|
||||
**文件**: `backend-single/src/main/java/com/emotion/dto/request/LoginRequest.java`
|
||||
|
||||
**修改前**:需要账号、密码、图形验证码、验证码key等字段
|
||||
|
||||
**修改后**:仅需2个字段
|
||||
```java
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class LoginRequest extends BaseRequest {
|
||||
|
||||
/**
|
||||
* 手机号
|
||||
*/
|
||||
@NotBlank(message = "手机号不能为空")
|
||||
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* 短信验证码
|
||||
*/
|
||||
@NotBlank(message = "验证码不能为空")
|
||||
@Size(min = 6, max = 6, message = "验证码必须为6位")
|
||||
private String smsCode;
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 优化登录逻辑
|
||||
|
||||
**文件**: `backend-single/src/main/java/com/emotion/service/impl/AuthServiceImpl.java`
|
||||
|
||||
#### 2.1 新的登录流程
|
||||
```java
|
||||
@Override
|
||||
public AuthResponse login(LoginRequest request) {
|
||||
// 1. 验证短信验证码
|
||||
if (!validateSmsCode(request.getPhone(), request.getSmsCode())) {
|
||||
throw new CaptchaException("验证码错误或已过期");
|
||||
}
|
||||
|
||||
// 2. 根据手机号查询用户
|
||||
User user = userService.getByPhone(request.getPhone());
|
||||
|
||||
// 3. 如果用户不存在,则自动注册
|
||||
if (user == null) {
|
||||
log.info("用户不存在,自动注册: phone={}", request.getPhone());
|
||||
user = autoRegisterUser(request.getPhone());
|
||||
} else {
|
||||
// 检查用户状态
|
||||
if (user.getStatus() != 1) {
|
||||
throw new AuthException("账号已被禁用");
|
||||
}
|
||||
log.info("用户登录: phone={}, userId={}", request.getPhone(), user.getId());
|
||||
}
|
||||
|
||||
// 4. 生成令牌并返回
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.2 自动注册用户
|
||||
```java
|
||||
/**
|
||||
* 自动注册用户(用于登录时用户不存在的情况)
|
||||
*
|
||||
* @param phone 手机号
|
||||
* @return 新创建的用户
|
||||
*/
|
||||
private User autoRegisterUser(String phone) {
|
||||
// 生成随机用户名:开心 + 6位随机大小写字母和数字
|
||||
String username = generateRandomUsername();
|
||||
|
||||
// 使用手机号作为账号
|
||||
String account = phone;
|
||||
|
||||
// 生成随机密码(用户可以后续修改)
|
||||
String randomPassword = generateRandomPassword();
|
||||
|
||||
// 创建用户
|
||||
User user = userService.createUser(
|
||||
account,
|
||||
username,
|
||||
randomPassword,
|
||||
null, // 邮箱为空
|
||||
phone
|
||||
);
|
||||
|
||||
log.info("自动注册用户成功: phone={}, username={}, userId={}", phone, username, user.getId());
|
||||
return user;
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.3 生成随机密码
|
||||
```java
|
||||
/**
|
||||
* 生成随机密码
|
||||
* 格式:8位随机大小写字母和数字
|
||||
*
|
||||
* @return 随机密码
|
||||
*/
|
||||
private String generateRandomPassword() {
|
||||
String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
Random random = new Random();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
int index = random.nextInt(chars.length());
|
||||
sb.append(chars.charAt(index));
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 优化短信验证码发送
|
||||
|
||||
**修改前**:检查手机号是否已注册,已注册则抛出异常
|
||||
|
||||
**修改后**:根据是否已注册返回不同的提示信息
|
||||
```java
|
||||
@Override
|
||||
public SmsCodeResponse sendSmsCode(String phone) {
|
||||
// 验证手机号格式
|
||||
if (!StringUtils.hasText(phone) || !phone.matches("^1[3-9]\\d{9}$")) {
|
||||
throw new BusinessException("手机号格式不正确");
|
||||
}
|
||||
|
||||
// 检查手机号是否已注册,用于提示信息
|
||||
boolean isRegistered = existsByPhone(phone);
|
||||
String message;
|
||||
if (isRegistered) {
|
||||
message = "验证码已发送,用于登录验证,有效期" + SMS_CODE_EXPIRE_MINUTES + "分钟";
|
||||
} else {
|
||||
message = "验证码已发送,用于注册验证,有效期" + SMS_CODE_EXPIRE_MINUTES + "分钟";
|
||||
}
|
||||
|
||||
// TODO: 接入真实的短信服务商(阿里云、腾讯云等)
|
||||
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={}, isRegistered={}", phone, code, isRegistered);
|
||||
|
||||
// 构建响应
|
||||
return SmsCodeResponse.builder()
|
||||
.code(code) // 开发环境返回验证码,生产环境应该删除此行
|
||||
.expiresIn((long) SMS_CODE_EXPIRE_MINUTES * 60)
|
||||
.message(message)
|
||||
.build();
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 更新Controller注解
|
||||
|
||||
**文件**: `backend-single/src/main/java/com/emotion/controller/AuthController.java`
|
||||
|
||||
```java
|
||||
/**
|
||||
* 用户登录(简化版:手机号+验证码,不存在则自动注册)
|
||||
*/
|
||||
@PostMapping("/login")
|
||||
@Operation(summary = "用户登录", description = "使用手机号和短信验证码登录,若用户不存在则自动注册")
|
||||
public Result<AuthResponse> login(@Valid @RequestBody LoginRequest request) {
|
||||
AuthResponse response = authService.login(request);
|
||||
return Result.success("登录成功", response);
|
||||
}
|
||||
```
|
||||
|
||||
## 📊 优化对比
|
||||
|
||||
| 项目 | 优化前 | 优化后 |
|
||||
|------|--------|--------|
|
||||
| 必填字段 | 账号、密码、验证码、验证码key | 手机号、短信验证码 |
|
||||
| 验证码类型 | 图形验证码 | 短信验证码 |
|
||||
| 用户不存在 | 提示错误 | 自动注册 |
|
||||
| 密码验证 | 需要 | 不需要 |
|
||||
| 登录流程 | 复杂 | 简单快捷 |
|
||||
|
||||
## 🔧 核心特性
|
||||
|
||||
### 1. 简化登录流程
|
||||
- ✅ 仅需2个字段:手机号、短信验证码
|
||||
- ✅ 无需记住密码
|
||||
- ✅ 用户不存在自动注册
|
||||
- ✅ 自动生成随机用户名和密码
|
||||
|
||||
### 2. 智能提示信息
|
||||
- ✅ 未注册用户:提示"用于注册验证"
|
||||
- ✅ 已注册用户:提示"用于登录验证"
|
||||
- ✅ 用户体验更友好
|
||||
|
||||
### 3. 自动注册机制
|
||||
- ✅ 自动生成用户名:开心 + 6位随机字符
|
||||
- ✅ 自动生成密码:8位随机字符
|
||||
- ✅ 使用手机号作为账号
|
||||
- ✅ 无缝登录体验
|
||||
|
||||
### 4. 安全性保障
|
||||
- ✅ 手机号格式验证
|
||||
- ✅ 短信验证码验证
|
||||
- ✅ 验证码过期检查
|
||||
- ✅ 验证码一次性使用
|
||||
- ✅ 用户状态检查
|
||||
|
||||
## 🚀 使用示例
|
||||
|
||||
### 场景1:新用户首次登录(自动注册)
|
||||
|
||||
#### 步骤1:获取短信验证码
|
||||
**请求**:
|
||||
```bash
|
||||
curl -X GET "http://localhost:19089/api/auth/sms-code?phone=13900139000"
|
||||
```
|
||||
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "验证码已发送",
|
||||
"data": {
|
||||
"code": "123456",
|
||||
"expiresIn": 300,
|
||||
"message": "验证码已发送,用于注册验证,有效期5分钟"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 步骤2:登录(自动注册)
|
||||
**请求**:
|
||||
```bash
|
||||
curl -X POST "http://localhost:19089/api/auth/login" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"phone": "13900139000",
|
||||
"smsCode": "123456"
|
||||
}'
|
||||
```
|
||||
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "登录成功",
|
||||
"data": {
|
||||
"accessToken": "eyJhbGciOiJIUzUxMiJ9...",
|
||||
"refreshToken": "eyJhbGciOiJIUzUxMiJ9...",
|
||||
"expiresIn": 86400,
|
||||
"userInfo": {
|
||||
"id": "f361c8648378565a91c6d799d641741f",
|
||||
"account": "13900139000",
|
||||
"username": "开心4FhbOl",
|
||||
"nickname": "开心4FhbOl",
|
||||
"phone": "13900139000",
|
||||
"memberLevel": "free"
|
||||
},
|
||||
"loginTime": "2025-10-06 23:14:57"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 场景2:已注册用户登录
|
||||
|
||||
#### 步骤1:获取短信验证码
|
||||
**请求**:
|
||||
```bash
|
||||
curl -X GET "http://localhost:19089/api/auth/sms-code?phone=13900139000"
|
||||
```
|
||||
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "验证码已发送",
|
||||
"data": {
|
||||
"code": "123456",
|
||||
"expiresIn": 300,
|
||||
"message": "验证码已发送,用于登录验证,有效期5分钟"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 步骤2:登录
|
||||
**请求**:
|
||||
```bash
|
||||
curl -X POST "http://localhost:19089/api/auth/login" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"phone": "13900139000",
|
||||
"smsCode": "123456"
|
||||
}'
|
||||
```
|
||||
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "登录成功",
|
||||
"data": {
|
||||
"accessToken": "eyJhbGciOiJIUzUxMiJ9...",
|
||||
"refreshToken": "eyJhbGciOiJIUzUxMiJ9...",
|
||||
"expiresIn": 86400,
|
||||
"userInfo": {
|
||||
"id": "f361c8648378565a91c6d799d641741f",
|
||||
"account": "13900139000",
|
||||
"username": "开心4FhbOl",
|
||||
"nickname": "开心4FhbOl",
|
||||
"phone": "13900139000",
|
||||
"memberLevel": "free"
|
||||
},
|
||||
"loginTime": "2025-10-06 23:15:18"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 📝 TODO事项
|
||||
|
||||
### 1. 接入真实短信服务
|
||||
|
||||
**位置**: `AuthServiceImpl.sendSmsCode()` 方法
|
||||
|
||||
**当前代码**:
|
||||
```java
|
||||
// TODO: 接入真实的短信服务商(阿里云、腾讯云等)
|
||||
// 目前使用固定验证码 123456
|
||||
String code = DEFAULT_SMS_CODE;
|
||||
```
|
||||
|
||||
**后续改进**:
|
||||
```java
|
||||
// 生成随机6位数字验证码
|
||||
String code = String.format("%06d", new Random().nextInt(1000000));
|
||||
|
||||
// 调用短信服务商API发送验证码
|
||||
// 示例:阿里云短信服务
|
||||
// smsService.sendSms(phone, code);
|
||||
```
|
||||
|
||||
### 2. 生产环境优化
|
||||
|
||||
**需要修改的地方**:
|
||||
1. **移除响应中的验证码**:
|
||||
```java
|
||||
return SmsCodeResponse.builder()
|
||||
// .code(code) // 生产环境删除此行
|
||||
.expiresIn((long) SMS_CODE_EXPIRE_MINUTES * 60)
|
||||
.message(message)
|
||||
.build();
|
||||
```
|
||||
|
||||
2. **添加发送频率限制**:
|
||||
- 同一手机号60秒内只能发送一次
|
||||
- 同一IP每天最多发送10次
|
||||
|
||||
3. **添加验证码尝试次数限制**:
|
||||
- 同一手机号最多尝试5次
|
||||
- 超过次数后需要重新获取验证码
|
||||
|
||||
## ✅ 验证清单
|
||||
|
||||
- [x] 编译成功,无错误
|
||||
- [x] LoginRequest简化为2个字段
|
||||
- [x] 实现自动注册逻辑
|
||||
- [x] 实现随机密码生成
|
||||
- [x] 优化短信验证码提示信息
|
||||
- [x] 更新Controller注解
|
||||
- [x] 测试新用户登录(自动注册)
|
||||
- [x] 测试已注册用户登录
|
||||
- [x] 添加详细的日志记录
|
||||
|
||||
## 🎉 总结
|
||||
|
||||
成功优化了登录接口,实现了以下目标:
|
||||
|
||||
1. ✅ **简化登录流程** - 仅需手机号和短信验证码
|
||||
2. ✅ **自动注册机制** - 用户不存在时自动注册
|
||||
3. ✅ **智能提示信息** - 根据用户状态返回不同提示
|
||||
4. ✅ **无缝用户体验** - 无需区分注册和登录
|
||||
5. ✅ **良好的代码质量** - 清晰的注释、完善的日志、标准的异常处理
|
||||
|
||||
现在用户可以通过简单的2步完成登录或注册:
|
||||
1. 输入手机号获取验证码
|
||||
2. 输入验证码完成登录(不存在则自动注册)
|
||||
|
||||
登录成功后自动返回访问令牌和用户信息,用户体验大大提升!
|
||||
|
||||
Reference in New Issue
Block a user