160 lines
5.7 KiB
Java
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;
|
|
}
|
|
} |