Files
backend/src/main/java/com/yundage/chat/service/UserService.java
2025-07-18 17:58:07 +08:00

160 lines
5.7 KiB
Java

package com.yundage.chat.service;
import com.yundage.chat.dto.*;
import com.yundage.chat.entity.User;
import com.yundage.chat.entity.PasswordResetToken;
import com.yundage.chat.mapper.UserMapper;
import com.yundage.chat.mapper.PasswordResetTokenMapper;
import com.yundage.chat.util.JwtUtil;
import com.mybatisflex.core.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.UUID;
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
@Autowired
private PasswordResetTokenMapper tokenMapper;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private JwtUtil jwtUtil;
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private EmailService emailService;
@Transactional
public AuthResponse register(RegisterRequest request) {
// 检查用户是否已存在
if (request.getEmail() != null && existsByEmail(request.getEmail())) {
throw new RuntimeException("邮箱已被注册");
}
if (request.getPhone() != null && existsByPhone(request.getPhone())) {
throw new RuntimeException("手机号已被注册");
}
// 创建新用户
User user = new User();
user.setUsername(request.getUsername());
user.setEmail(request.getEmail());
user.setPhone(request.getPhone());
user.setPasswordHash(passwordEncoder.encode(request.getPassword()));
user.setCreatedAt(LocalDateTime.now());
user.setUpdatedAt(LocalDateTime.now());
userMapper.insert(user);
// 生成JWT令牌
String token = jwtUtil.generateToken(user.getUsername(), user.getId());
return new AuthResponse(token, user.getId(), user.getDisplayName(),
user.getEmail(), user.getPhone());
}
public AuthResponse login(LoginRequest request) {
try {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword())
);
User user = (User) authentication.getPrincipal();
// 更新最后登录时间
user.setLastLoginAt(LocalDateTime.now());
userMapper.update(user);
// 生成JWT令牌
String token = jwtUtil.generateToken(user.getUsername(), user.getId());
return new AuthResponse(token, user.getId(), user.getDisplayName(),
user.getEmail(), user.getPhone());
} catch (AuthenticationException e) {
throw new RuntimeException("用户名或密码错误");
}
}
@Transactional
public void requestPasswordReset(PasswordResetRequest request) {
User user = findByEmail(request.getEmail());
if (user == null) {
throw new RuntimeException("用户不存在");
}
// 生成重置令牌
String token = UUID.randomUUID().toString();
LocalDateTime expiresAt = LocalDateTime.now().plusHours(1); // 1小时后过期
PasswordResetToken resetToken = new PasswordResetToken(user.getId(), token, expiresAt);
tokenMapper.insert(resetToken);
// 发送重置邮件
emailService.sendPasswordResetEmail(user.getEmail(), user.getDisplayName(), token);
}
@Transactional
public void resetPassword(ResetPasswordRequest request) {
// 查找重置令牌
QueryWrapper queryWrapper = QueryWrapper.create()
.where(PasswordResetToken::getToken).eq(request.getToken())
.and(PasswordResetToken::getUsed).eq(false);
PasswordResetToken resetToken = tokenMapper.selectOneByQuery(queryWrapper);
if (resetToken == null || !resetToken.isValid()) {
throw new RuntimeException("重置令牌无效或已过期");
}
// 更新用户密码
User user = userMapper.selectOneById(resetToken.getUserId());
if (user == null) {
throw new RuntimeException("用户不存在");
}
user.setPasswordHash(passwordEncoder.encode(request.getNewPassword()));
user.setUpdatedAt(LocalDateTime.now());
userMapper.update(user);
// 标记令牌为已使用
resetToken.setUsed(true);
tokenMapper.update(resetToken);
}
public User findByEmail(String email) {
QueryWrapper queryWrapper = QueryWrapper.create()
.where(User::getEmail).eq(email);
return userMapper.selectOneByQuery(queryWrapper);
}
public User findByPhone(String phone) {
QueryWrapper queryWrapper = QueryWrapper.create()
.where(User::getPhone).eq(phone);
return userMapper.selectOneByQuery(queryWrapper);
}
public boolean existsByEmail(String email) {
return findByEmail(email) != null;
}
public boolean existsByPhone(String phone) {
return findByPhone(phone) != null;
}
}