代码优化
This commit is contained in:
@@ -6,10 +6,14 @@ import com.emotion.dto.request.RegisterRequest;
|
||||
import com.emotion.dto.request.RefreshTokenRequest;
|
||||
import com.emotion.dto.response.AuthResponse;
|
||||
import com.emotion.dto.response.CaptchaResponse;
|
||||
import com.emotion.dto.response.SmsCodeResponse;
|
||||
import com.emotion.dto.response.UserInfoResponse;
|
||||
import com.emotion.service.AuthService;
|
||||
import com.emotion.service.TokenService;
|
||||
import com.emotion.util.UserContextUtils;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@@ -24,6 +28,7 @@ import javax.validation.Valid;
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/auth")
|
||||
@Tag(name = "认证管理", description = "用户注册、登录、验证码等认证相关接口")
|
||||
public class AuthController {
|
||||
|
||||
@Autowired
|
||||
@@ -33,18 +38,20 @@ public class AuthController {
|
||||
private TokenService tokenService;
|
||||
|
||||
/**
|
||||
* 用户登录
|
||||
* 用户登录(简化版:手机号+验证码,不存在则自动注册)
|
||||
*/
|
||||
@PostMapping("/login")
|
||||
@Operation(summary = "用户登录", description = "使用手机号和短信验证码登录,若用户不存在则自动注册")
|
||||
public Result<AuthResponse> login(@Valid @RequestBody LoginRequest request) {
|
||||
AuthResponse response = authService.login(request);
|
||||
return Result.success("登录成功", response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户注册
|
||||
* 用户注册(简化版:仅需手机号、密码和短信验证码)
|
||||
*/
|
||||
@PostMapping("/register")
|
||||
@Operation(summary = "用户注册", description = "使用手机号、密码和短信验证码进行注册")
|
||||
public Result<AuthResponse> register(@Valid @RequestBody RegisterRequest request) {
|
||||
AuthResponse response = authService.register(request);
|
||||
return Result.success("注册成功", response);
|
||||
@@ -60,14 +67,27 @@ public class AuthController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成验证码
|
||||
* 生成验证码(图形验证码,用于登录)
|
||||
*/
|
||||
@GetMapping("/captcha")
|
||||
@Operation(summary = "获取图形验证码", description = "用于登录时的图形验证码")
|
||||
public Result<CaptchaResponse> generateCaptcha() {
|
||||
CaptchaResponse response = authService.generateCaptcha();
|
||||
return Result.success(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取短信验证码(用于注册)
|
||||
*/
|
||||
@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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户登出
|
||||
*/
|
||||
|
||||
@@ -1,44 +1,60 @@
|
||||
package com.emotion.controller;
|
||||
|
||||
import com.emotion.common.Result;
|
||||
import com.emotion.dto.request.TokenRequest;
|
||||
import com.emotion.dto.response.UserInfoResponse;
|
||||
import com.emotion.service.TokenService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* Token控制器
|
||||
* 提供基于请求头Authorization的token验证和用户信息获取功能
|
||||
*
|
||||
* @author emotion-museum
|
||||
* @date 2025-07-23
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/token")
|
||||
@Tag(name = "Token管理", description = "Token验证和用户信息获取")
|
||||
public class TokenController {
|
||||
|
||||
@Autowired
|
||||
private TokenService tokenService;
|
||||
|
||||
/**
|
||||
* 通过token获取用户信息
|
||||
* 通过请求头中的token获取用户信息
|
||||
* Token应该在请求头中以 "Authorization: Bearer {token}" 的形式传递
|
||||
*/
|
||||
@PostMapping("/user-info")
|
||||
public Result<UserInfoResponse> getUserInfoByToken(@RequestBody @Validated TokenRequest request) {
|
||||
UserInfoResponse userInfo = tokenService.getUserInfoByToken(request.getToken());
|
||||
@GetMapping("/user-info")
|
||||
@Operation(summary = "获取用户信息", description = "通过请求头中的token获取当前用户信息")
|
||||
public Result<UserInfoResponse> getUserInfoByToken(HttpServletRequest request) {
|
||||
UserInfoResponse userInfo = tokenService.getUserInfoByToken(request);
|
||||
return Result.success(userInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过token获取用户名
|
||||
* 通过请求头中的token获取用户名
|
||||
* Token应该在请求头中以 "Authorization: Bearer {token}" 的形式传递
|
||||
*/
|
||||
@PostMapping("/username")
|
||||
public Result<String> getUsernameByToken(@RequestBody @Validated TokenRequest request) {
|
||||
String username = tokenService.getUsernameByToken(request.getToken());
|
||||
@GetMapping("/username")
|
||||
@Operation(summary = "获取用户名", description = "通过请求头中的token获取当前用户名")
|
||||
public Result<String> getUsernameByToken(HttpServletRequest request) {
|
||||
String username = tokenService.getUsernameByToken(request);
|
||||
return Result.success(username);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证token并返回用户ID
|
||||
* 验证请求头中的token并返回用户ID
|
||||
* Token应该在请求头中以 "Authorization: Bearer {token}" 的形式传递
|
||||
*/
|
||||
@PostMapping("/validate")
|
||||
public Result<String> validateTokenAndGetUserId(@RequestBody @Validated TokenRequest request) {
|
||||
String userId = tokenService.validateTokenAndGetUserId(request.getToken());
|
||||
@GetMapping("/validate")
|
||||
@Operation(summary = "验证Token", description = "验证请求头中的token并返回用户ID")
|
||||
public Result<String> validateTokenAndGetUserId(HttpServletRequest request) {
|
||||
String userId = tokenService.validateTokenAndGetUserId(request);
|
||||
return Result.success(userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,38 +4,31 @@ import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Pattern;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
/**
|
||||
* 登录请求
|
||||
*
|
||||
* 简化版:仅需手机号和短信验证码
|
||||
*
|
||||
* @author emotion-museum
|
||||
* @date 2025-07-23
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class LoginRequest extends BaseRequest {
|
||||
|
||||
|
||||
/**
|
||||
* 账号
|
||||
* 手机号
|
||||
*/
|
||||
@NotBlank(message = "账号不能为空")
|
||||
private String account;
|
||||
|
||||
@NotBlank(message = "手机号不能为空")
|
||||
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
@NotBlank(message = "密码不能为空")
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 验证码
|
||||
* 短信验证码
|
||||
*/
|
||||
@NotBlank(message = "验证码不能为空")
|
||||
private String captcha;
|
||||
|
||||
/**
|
||||
* 验证码key
|
||||
*/
|
||||
@NotBlank(message = "验证码key不能为空")
|
||||
private String captchaKey;
|
||||
@Size(min = 6, max = 6, message = "验证码必须为6位")
|
||||
private String smsCode;
|
||||
}
|
||||
|
||||
@@ -3,72 +3,39 @@ package com.emotion.dto.request;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Pattern;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
/**
|
||||
* 注册请求
|
||||
*
|
||||
* 简化版:仅需要手机号、密码和验证码
|
||||
*
|
||||
* @author emotion-museum
|
||||
* @date 2025-07-23
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class RegisterRequest extends BaseRequest {
|
||||
|
||||
|
||||
/**
|
||||
* 账号
|
||||
* 手机号(作为账号)
|
||||
*/
|
||||
@NotBlank(message = "账号不能为空")
|
||||
@Size(min = 3, max = 20, message = "账号长度必须在3-20个字符之间")
|
||||
private String account;
|
||||
|
||||
@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 = "确认密码不能为空")
|
||||
private String confirmPassword;
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 昵称
|
||||
*/
|
||||
private String nickname;
|
||||
|
||||
/**
|
||||
* 邮箱
|
||||
*/
|
||||
@Email(message = "邮箱格式不正确")
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 手机号
|
||||
*/
|
||||
@Pattern(regexp = "^$|^1[3-9]\\d{9}$", message = "手机号格式不正确")
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* 验证码
|
||||
* 短信验证码
|
||||
*/
|
||||
@NotBlank(message = "验证码不能为空")
|
||||
private String captcha;
|
||||
|
||||
/**
|
||||
* 验证码key
|
||||
*/
|
||||
@NotBlank(message = "验证码key不能为空")
|
||||
private String captchaKey;
|
||||
@Size(min = 6, max = 6, message = "验证码必须为6位")
|
||||
private String smsCode;
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
package com.emotion.dto.request;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
public class TokenRequest {
|
||||
@NotBlank(message = "token不能为空")
|
||||
private String token;
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public void setToken(String token) {
|
||||
this.token = token;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.emotion.dto.response;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 短信验证码响应
|
||||
*
|
||||
* @author emotion-museum
|
||||
* @date 2025-10-06
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SmsCodeResponse {
|
||||
|
||||
/**
|
||||
* 验证码(开发环境返回,生产环境不返回)
|
||||
*/
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 过期时间(秒)
|
||||
*/
|
||||
private Long expiresIn;
|
||||
|
||||
/**
|
||||
* 提示信息
|
||||
*/
|
||||
private String message;
|
||||
}
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
package com.emotion.dto.response;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* WebSocket响应对象
|
||||
*
|
||||
* @author emotion-museum
|
||||
* @date 2025-09-08
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class WebSocketResponse extends BaseResponse {
|
||||
|
||||
/**
|
||||
* 消息ID
|
||||
*/
|
||||
private String messageId;
|
||||
|
||||
/**
|
||||
* 会话ID
|
||||
*/
|
||||
private String conversationId;
|
||||
|
||||
/**
|
||||
* 消息类型
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 消息内容
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 发送者ID
|
||||
*/
|
||||
private String senderId;
|
||||
|
||||
/**
|
||||
* 发送者类型
|
||||
*/
|
||||
private String senderType;
|
||||
|
||||
/**
|
||||
* 消息状态
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 扩展数据
|
||||
*/
|
||||
private Object data;
|
||||
}
|
||||
@@ -22,7 +22,7 @@ import java.time.LocalDateTime;
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@TableName("achievement")
|
||||
@TableName("t_achievement")
|
||||
public class Achievement extends BaseEntity {
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,7 +19,7 @@ import lombok.EqualsAndHashCode;
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@TableName("comment")
|
||||
@TableName("t_comment")
|
||||
public class Comment extends BaseEntity {
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,7 +19,7 @@ import lombok.EqualsAndHashCode;
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@TableName("community_post")
|
||||
@TableName("t_community_post")
|
||||
public class CommunityPost extends BaseEntity {
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,7 +22,7 @@ import java.time.LocalDateTime;
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@TableName("conversation")
|
||||
@TableName("t_conversation")
|
||||
public class Conversation extends BaseEntity {
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,7 +22,7 @@ import java.time.LocalDateTime;
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@TableName("coze_api_call")
|
||||
@TableName("t_coze_api_call")
|
||||
public class CozeApiCall extends BaseEntity {
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,7 +22,7 @@ import java.time.LocalDateTime;
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@TableName("diary_comment")
|
||||
@TableName("t_diary_comment")
|
||||
public class DiaryComment extends BaseEntity {
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,7 +22,7 @@ import java.time.LocalDateTime;
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@TableName("diary_post")
|
||||
@TableName("t_diary_post")
|
||||
public class DiaryPost extends BaseEntity {
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,7 +22,7 @@ import java.time.LocalDateTime;
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@TableName("emotion_analysis")
|
||||
@TableName("t_emotion_analysis")
|
||||
public class EmotionAnalysis extends BaseEntity {
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,7 +22,7 @@ import java.time.LocalDate;
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@TableName("emotion_record")
|
||||
@TableName("t_emotion_record")
|
||||
public class EmotionRecord extends BaseEntity {
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,7 +22,7 @@ import java.time.LocalDateTime;
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@TableName("growth_topic")
|
||||
@TableName("t_growth_topic")
|
||||
public class GrowthTopic extends BaseEntity {
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,7 +21,7 @@ import java.time.LocalDateTime;
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@TableName("guest_user")
|
||||
@TableName("t_guest_user")
|
||||
public class GuestUser extends BaseEntity {
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,7 +22,7 @@ import java.time.LocalDateTime;
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@TableName("location_pin")
|
||||
@TableName("t_location_pin")
|
||||
public class LocationPin extends BaseEntity {
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,7 +22,7 @@ import java.time.LocalDateTime;
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@TableName("message")
|
||||
@TableName("t_message")
|
||||
public class Message extends BaseEntity {
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,7 +21,7 @@ import java.time.LocalDateTime;
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@TableName("reward")
|
||||
@TableName("t_reward")
|
||||
public class Reward extends BaseEntity {
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,7 +21,7 @@ import java.time.LocalDateTime;
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@TableName("topic_interaction")
|
||||
@TableName("t_topic_interaction")
|
||||
public class TopicInteraction extends BaseEntity {
|
||||
|
||||
/**
|
||||
|
||||
@@ -23,7 +23,7 @@ import java.time.LocalDateTime;
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@TableName("user")
|
||||
@TableName("t_user")
|
||||
public class User extends BaseEntity {
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,7 +19,7 @@ import lombok.EqualsAndHashCode;
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@TableName("user_stats")
|
||||
@TableName("t_user_stats")
|
||||
public class UserStats extends BaseEntity {
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.emotion.dto.request.LoginRequest;
|
||||
import com.emotion.dto.request.RegisterRequest;
|
||||
import com.emotion.dto.response.AuthResponse;
|
||||
import com.emotion.dto.response.CaptchaResponse;
|
||||
import com.emotion.dto.response.SmsCodeResponse;
|
||||
import com.emotion.dto.response.UserInfoResponse;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@@ -136,4 +137,21 @@ public interface AuthService {
|
||||
* @return 是否存在
|
||||
*/
|
||||
boolean existsByPhone(String phone);
|
||||
|
||||
/**
|
||||
* 发送短信验证码
|
||||
*
|
||||
* @param phone 手机号
|
||||
* @return 短信验证码响应
|
||||
*/
|
||||
SmsCodeResponse sendSmsCode(String phone);
|
||||
|
||||
/**
|
||||
* 验证短信验证码
|
||||
*
|
||||
* @param phone 手机号
|
||||
* @param code 验证码
|
||||
* @return 是否验证成功
|
||||
*/
|
||||
boolean validateSmsCode(String phone, String code);
|
||||
}
|
||||
@@ -9,14 +9,16 @@ import com.emotion.dto.request.UserProfileUpdateRequest;
|
||||
import com.emotion.dto.response.UserResponse;
|
||||
import com.emotion.entity.User;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 用户服务接口
|
||||
*
|
||||
*
|
||||
* @author emotion-museum
|
||||
* @date 2025-07-23
|
||||
*/
|
||||
public interface UserService extends IService<User> {
|
||||
|
||||
|
||||
/**
|
||||
* 分页查询用户响应
|
||||
*/
|
||||
@@ -51,4 +53,39 @@ public interface UserService extends IService<User> {
|
||||
* 删除用户
|
||||
*/
|
||||
boolean deleteUser(String id);
|
||||
|
||||
/**
|
||||
* 根据账号获取用户
|
||||
*/
|
||||
User getByAccount(String account);
|
||||
|
||||
/**
|
||||
* 根据邮箱获取用户
|
||||
*/
|
||||
User getByEmail(String email);
|
||||
|
||||
/**
|
||||
* 根据手机号获取用户
|
||||
*/
|
||||
User getByPhone(String phone);
|
||||
|
||||
/**
|
||||
* 创建用户
|
||||
*
|
||||
* @param account 账号
|
||||
* @param username 用户名
|
||||
* @param password 密码(明文,会在方法内加密)
|
||||
* @param email 邮箱(可为null)
|
||||
* @param phone 手机号(可为null)
|
||||
* @return 创建的用户
|
||||
*/
|
||||
User createUser(String account, String username, String password, String email, String phone);
|
||||
|
||||
/**
|
||||
* 更新用户最后活跃时间
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param lastActiveTime 最后活跃时间
|
||||
*/
|
||||
void updateLastActiveTime(String userId, LocalDateTime lastActiveTime);
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import com.emotion.dto.request.LoginRequest;
|
||||
import com.emotion.dto.request.RegisterRequest;
|
||||
import com.emotion.dto.response.AuthResponse;
|
||||
import com.emotion.dto.response.CaptchaResponse;
|
||||
import com.emotion.dto.response.SmsCodeResponse;
|
||||
import com.emotion.dto.response.UserInfoResponse;
|
||||
import com.emotion.entity.User;
|
||||
import com.emotion.exception.AuthException;
|
||||
@@ -61,34 +62,36 @@ public class AuthServiceImpl implements AuthService {
|
||||
private TokenUtil tokenUtil;
|
||||
|
||||
private static final String CAPTCHA_PREFIX = "captcha:";
|
||||
private static final String SMS_CODE_PREFIX = "sms_code:";
|
||||
private static final String TOKEN_PREFIX = "token:";
|
||||
private static final String REFRESH_TOKEN_PREFIX = "refresh_token:";
|
||||
private static final int CAPTCHA_EXPIRE_MINUTES = 5;
|
||||
private static final int SMS_CODE_EXPIRE_MINUTES = 5;
|
||||
private static final int TOKEN_EXPIRE_HOURS = 24;
|
||||
private static final int REFRESH_TOKEN_EXPIRE_DAYS = 7;
|
||||
private static final String DEFAULT_SMS_CODE = "123456";
|
||||
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
@Override
|
||||
public AuthResponse login(LoginRequest request) {
|
||||
// 验证验证码
|
||||
if (!validateCaptcha(request.getCaptchaKey(), request.getCaptcha())) {
|
||||
// 验证短信验证码
|
||||
if (!validateSmsCode(request.getPhone(), request.getSmsCode())) {
|
||||
throw new CaptchaException("验证码错误或已过期");
|
||||
}
|
||||
|
||||
// 根据账号查询用户
|
||||
User user = userService.getByAccount(request.getAccount());
|
||||
// 根据手机号查询用户
|
||||
User user = userService.getByPhone(request.getPhone());
|
||||
|
||||
// 如果用户不存在,则自动注册
|
||||
if (user == null) {
|
||||
throw new AuthException("账号不存在");
|
||||
}
|
||||
|
||||
// 验证密码(这里应该使用加密后的密码比较)
|
||||
if (!verifyPassword(request.getPassword(), user.getPassword())) {
|
||||
throw new AuthException("密码错误");
|
||||
}
|
||||
|
||||
// 检查用户状态
|
||||
if (user.getStatus() != 1) {
|
||||
throw new AuthException("账号已被禁用");
|
||||
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());
|
||||
}
|
||||
|
||||
// 生成令牌
|
||||
@@ -111,61 +114,31 @@ public class AuthServiceImpl implements AuthService {
|
||||
|
||||
@Override
|
||||
public AuthResponse register(RegisterRequest request) {
|
||||
// 验证验证码
|
||||
if (!validateCaptcha(request.getCaptchaKey(), request.getCaptcha())) {
|
||||
// 验证短信验证码
|
||||
if (!validateSmsCode(request.getPhone(), request.getSmsCode())) {
|
||||
throw new CaptchaException("验证码错误或已过期");
|
||||
}
|
||||
|
||||
// 验证密码确认
|
||||
if (!request.getPassword().equals(request.getConfirmPassword())) {
|
||||
throw new BusinessException("密码与确认密码不一致");
|
||||
// 检查手机号是否已存在
|
||||
if (userService.getByPhone(request.getPhone()) != null) {
|
||||
throw new BusinessException("手机号已被注册");
|
||||
}
|
||||
|
||||
// 检查账号是否已存在
|
||||
if (userService.getByAccount(request.getAccount()) != null) {
|
||||
throw new BusinessException("账号已存在");
|
||||
}
|
||||
// 生成随机用户名:开心 + 6位随机大小写字母和数字
|
||||
String username = generateRandomUsername();
|
||||
|
||||
// 检查邮箱是否已存在(只有当邮箱不为空时才检查)
|
||||
if (StringUtils.hasText(request.getEmail()) && userService.getByEmail(request.getEmail()) != null) {
|
||||
throw new BusinessException("邮箱已被使用");
|
||||
}
|
||||
|
||||
// 检查手机号是否已存在(只有当手机号不为空时才检查)
|
||||
if (StringUtils.hasText(request.getPhone()) && userService.getByPhone(request.getPhone()) != null) {
|
||||
throw new BusinessException("手机号已被使用");
|
||||
}
|
||||
|
||||
// 处理用户名:如果为空则使用账号
|
||||
String username = StringUtils.hasText(request.getUsername()) ? request.getUsername() : request.getAccount();
|
||||
|
||||
// 处理邮箱:如果为空字符串则设为null
|
||||
String email = StringUtils.hasText(request.getEmail()) ? request.getEmail() : null;
|
||||
|
||||
// 处理手机号:如果为空字符串则设为null
|
||||
String phone = StringUtils.hasText(request.getPhone()) ? request.getPhone() : null;
|
||||
// 使用手机号作为账号
|
||||
String account = request.getPhone();
|
||||
|
||||
// 创建用户(密码在UserService中加密,这里不需要预先加密)
|
||||
User user = userService.createUser(
|
||||
request.getAccount(),
|
||||
account,
|
||||
username,
|
||||
request.getPassword(),
|
||||
email,
|
||||
phone
|
||||
null, // 邮箱为空
|
||||
request.getPhone()
|
||||
);
|
||||
|
||||
// 设置昵称(如果昵称为空则使用用户名)
|
||||
if (StringUtils.hasText(request.getNickname())) {
|
||||
user.setNickname(request.getNickname());
|
||||
} else if (StringUtils.hasText(username)) {
|
||||
user.setNickname(username);
|
||||
}
|
||||
|
||||
// 如果有昵称变更,更新用户信息
|
||||
if (StringUtils.hasText(user.getNickname())) {
|
||||
userService.updateById(user);
|
||||
}
|
||||
|
||||
// 生成令牌
|
||||
String accessToken = generateAccessToken(user);
|
||||
String refreshToken = generateRefreshToken(user);
|
||||
@@ -178,6 +151,7 @@ public class AuthServiceImpl implements AuthService {
|
||||
response.setUserInfo(convertToUserInfoResponse(user));
|
||||
response.setLoginTime(LocalDateTime.now().format(DATE_TIME_FORMATTER));
|
||||
|
||||
log.info("用户注册成功: phone={}, username={}", request.getPhone(), username);
|
||||
return response;
|
||||
}
|
||||
|
||||
@@ -510,4 +484,132 @@ public class AuthServiceImpl implements AuthService {
|
||||
User user = userService.getByPhone(phone);
|
||||
return user != null;
|
||||
}
|
||||
|
||||
@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: 接入真实的短信服务商(阿里云、腾讯云等)
|
||||
// 目前使用固定验证码 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={}, isRegistered={}", phone, code, isRegistered);
|
||||
|
||||
// 构建响应
|
||||
return SmsCodeResponse.builder()
|
||||
.code(code) // 开发环境返回验证码,生产环境应该删除此行
|
||||
.expiresIn((long) SMS_CODE_EXPIRE_MINUTES * 60)
|
||||
.message(message)
|
||||
.build();
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成随机用户名
|
||||
* 格式:开心 + 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动注册用户(用于登录时用户不存在的情况)
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成随机密码
|
||||
* 格式: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();
|
||||
}
|
||||
}
|
||||
@@ -245,6 +245,69 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
|
||||
return this.updateById(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getByAccount(String account) {
|
||||
if (!StringUtils.hasText(account)) {
|
||||
return null;
|
||||
}
|
||||
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(User::getAccount, account)
|
||||
.eq(User::getIsDeleted, 0);
|
||||
return this.getOne(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getByEmail(String email) {
|
||||
if (!StringUtils.hasText(email)) {
|
||||
return null;
|
||||
}
|
||||
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(User::getEmail, email)
|
||||
.eq(User::getIsDeleted, 0);
|
||||
return this.getOne(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getByPhone(String phone) {
|
||||
if (!StringUtils.hasText(phone)) {
|
||||
return null;
|
||||
}
|
||||
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(User::getPhone, phone)
|
||||
.eq(User::getIsDeleted, 0);
|
||||
return this.getOne(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public User createUser(String account, String username, String password, String email, String phone) {
|
||||
User user = new User();
|
||||
user.setAccount(account);
|
||||
user.setUsername(username);
|
||||
user.setNickname(username); // 默认昵称与用户名相同
|
||||
user.setPassword(passwordEncoder.encode(password)); // 加密密码
|
||||
user.setEmail(email);
|
||||
user.setPhone(phone);
|
||||
user.setMemberLevel("free"); // 默认免费会员
|
||||
user.setStatus(1); // 默认启用
|
||||
user.setIsVerified(0); // 默认未验证
|
||||
user.setLastActiveTime(LocalDateTime.now());
|
||||
|
||||
this.save(user);
|
||||
return user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLastActiveTime(String userId, LocalDateTime lastActiveTime) {
|
||||
if (!StringUtils.hasText(userId) || lastActiveTime == null) {
|
||||
return;
|
||||
}
|
||||
User user = this.getById(userId);
|
||||
if (user != null && user.getIsDeleted() == 0) {
|
||||
user.setLastActiveTime(lastActiveTime);
|
||||
this.updateById(user);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为响应对象
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user