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; } }