feat: 在AccountService中添加用户删除逻辑的详细检查,包括关联数据的验证和日志记录,增强用户管理的安全性

This commit is contained in:
zyh
2025-10-03 11:04:22 +08:00
parent c6238277b8
commit 29742cb732

View File

@@ -1,29 +1,47 @@
package com.gameplatform.server.service.account; package com.gameplatform.server.service.account;
import com.gameplatform.server.mapper.account.UserAccountMapper; import com.gameplatform.server.mapper.account.UserAccountMapper;
import com.gameplatform.server.mapper.agent.AgentPointsTxMapper;
import com.gameplatform.server.mapper.agent.LinkBatchMapper;
import com.gameplatform.server.mapper.agent.LinkTaskMapper;
import com.gameplatform.server.model.dto.account.AccountCreateRequest; import com.gameplatform.server.model.dto.account.AccountCreateRequest;
import com.gameplatform.server.model.dto.account.AccountResponse; import com.gameplatform.server.model.dto.account.AccountResponse;
import com.gameplatform.server.model.dto.account.AccountUpdateRequest; import com.gameplatform.server.model.dto.account.AccountUpdateRequest;
import com.gameplatform.server.model.dto.account.PointsBalanceResponse; import com.gameplatform.server.model.dto.account.PointsBalanceResponse;
import com.gameplatform.server.model.dto.common.PageResult; import com.gameplatform.server.model.dto.common.PageResult;
import com.gameplatform.server.model.entity.account.UserAccount; import com.gameplatform.server.model.entity.account.UserAccount;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers; import reactor.core.scheduler.Schedulers;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Service @Service
public class AccountService { public class AccountService {
private static final Logger log = LoggerFactory.getLogger(AccountService.class);
private final UserAccountMapper mapper; private final UserAccountMapper mapper;
private final PasswordEncoder passwordEncoder; private final PasswordEncoder passwordEncoder;
private final LinkTaskMapper linkTaskMapper;
private final LinkBatchMapper linkBatchMapper;
private final AgentPointsTxMapper agentPointsTxMapper;
public AccountService(UserAccountMapper mapper, PasswordEncoder passwordEncoder) { public AccountService(UserAccountMapper mapper,
PasswordEncoder passwordEncoder,
LinkTaskMapper linkTaskMapper,
LinkBatchMapper linkBatchMapper,
AgentPointsTxMapper agentPointsTxMapper) {
this.mapper = mapper; this.mapper = mapper;
this.passwordEncoder = passwordEncoder; this.passwordEncoder = passwordEncoder;
this.linkTaskMapper = linkTaskMapper;
this.linkBatchMapper = linkBatchMapper;
this.agentPointsTxMapper = agentPointsTxMapper;
} }
public Mono<PageResult<AccountResponse>> list(String userType, String status, String keyword, public Mono<PageResult<AccountResponse>> list(String userType, String status, String keyword,
@@ -166,27 +184,74 @@ public class AccountService {
@Transactional @Transactional
public Mono<Boolean> delete(Long id, Long currentUserId) { public Mono<Boolean> delete(Long id, Long currentUserId) {
return Mono.fromCallable(() -> { return Mono.fromCallable(() -> {
// 检查用户是否存在 log.info("开始删除用户账户: id={}, 操作者={}", id, currentUserId);
// 1. 检查用户是否存在
UserAccount user = mapper.selectById(id); UserAccount user = mapper.selectById(id);
if (user == null) { if (user == null) {
log.warn("用户不存在: id={}", id);
throw new IllegalArgumentException("用户不存在"); throw new IllegalArgumentException("用户不存在");
} }
// 不能删除自己 log.info("准备删除用户: username={}, userType={}", user.getUsername(), user.getUserType());
// 2. 不能删除自己
if (id.equals(currentUserId)) { if (id.equals(currentUserId)) {
log.warn("尝试删除自己: userId={}", id);
throw new IllegalArgumentException("不能删除当前登录的用户"); throw new IllegalArgumentException("不能删除当前登录的用户");
} }
// 如果要删除的是管理员,检查是否是最后一个管理员 // 3. 如果要删除的是管理员,检查是否是最后一个管理员
if ("ADMIN".equals(user.getUserType())) { if ("ADMIN".equals(user.getUserType())) {
long adminCount = mapper.countByFilter("ADMIN", "ENABLED", null); long adminCount = mapper.countByFilter("ADMIN", "ENABLED", null);
if (adminCount <= 1) { if (adminCount <= 1) {
log.warn("尝试删除最后一个管理员: userId={}", id);
throw new IllegalArgumentException("不能删除最后一个管理员账户"); throw new IllegalArgumentException("不能删除最后一个管理员账户");
} }
} }
// 执行删除 // 4. 检查是否有关联数据(对所有用户类型都检查)
return mapper.deleteById(id) > 0; List<String> blockReasons = new ArrayList<>();
// 检查链接任务
long linkTaskCount = linkTaskMapper.countByAgentId(id);
if (linkTaskCount > 0) {
blockReasons.add(String.format("该用户还有 %d 个链接任务", linkTaskCount));
log.info("用户 {} 有 {} 个链接任务", id, linkTaskCount);
}
// 检查批次记录
long batchCount = linkBatchMapper.countByAgentId(id);
if (batchCount > 0) {
blockReasons.add(String.format("该用户还有 %d 个批次记录", batchCount));
log.info("用户 {} 有 {} 个批次记录", id, batchCount);
}
// 检查积分交易记录
long pointsTxCount = agentPointsTxMapper.countByAccountId(id);
if (pointsTxCount > 0) {
blockReasons.add(String.format("该用户还有 %d 条积分交易记录", pointsTxCount));
log.info("用户 {} 有 {} 条积分交易记录", id, pointsTxCount);
}
// 如果有阻止删除的原因,抛出友好的错误提示
if (!blockReasons.isEmpty()) {
String errorMessage = String.format("无法删除用户 '%s'%s。请先清理这些数据后再删除。",
user.getUsername(),
String.join("", blockReasons));
log.warn("删除用户被阻止: userId={}, 原因: {}", id, errorMessage);
throw new IllegalArgumentException(errorMessage);
}
// 5. 执行删除
boolean deleted = mapper.deleteById(id) > 0;
if (deleted) {
log.info("用户删除成功: id={}, username={}", id, user.getUsername());
} else {
log.warn("用户删除失败: id={}", id);
}
return deleted;
}) })
.subscribeOn(Schedulers.boundedElastic()); .subscribeOn(Schedulers.boundedElastic());
} }