fix(security): enforce owner checks for martial user resources

This commit is contained in:
2026-02-15 17:53:13 +08:00
parent 543459ad0b
commit 728cbdf57c
6 changed files with 257 additions and 74 deletions
@@ -1,8 +1,6 @@
package org.springblade.modules.martial.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import java.time.LocalDateTime;
import java.util.List;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
@@ -23,6 +21,9 @@ import org.springblade.modules.martial.service.IMartialAthleteService;
import org.springblade.modules.martial.service.IMartialCompetitionService;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.List;
/**
* 参赛选手 控制器
*
@@ -44,7 +45,17 @@ public class MartialAthleteController extends BladeController {
@GetMapping("/detail")
@Operation(summary = "详情", description = "传入ID")
public R<MartialAthlete> detail(@RequestParam Long id) {
Long userId = AuthUtil.getUserId();
if (userId == null || userId <= 0) {
return R.fail("请先登录");
}
MartialAthlete detail = athleteService.getById(id);
if (detail == null) {
return R.fail("选手不存在");
}
if (!isAdminUser() && !userId.equals(detail.getCreateUser())) {
return R.fail("无权限访问该选手");
}
return R.data(detail);
}
@@ -54,6 +65,13 @@ public class MartialAthleteController extends BladeController {
@GetMapping("/list")
@Operation(summary = "分页列表", description = "分页查询")
public R<IPage<MartialAthleteVO>> list(MartialAthlete athlete, Query query, @RequestParam(required = false, defaultValue = "false") Boolean includeTeamRecords) {
Long userId = AuthUtil.getUserId();
if (userId == null || userId <= 0) {
return R.fail("请先登录");
}
if (!isAdminUser()) {
athlete.setCreateUser(userId);
}
IPage<MartialAthleteVO> pages = athleteService.selectAthleteVOPage(Condition.getPage(query), athlete, includeTeamRecords);
return R.data(pages);
}
@@ -100,10 +118,21 @@ public class MartialAthleteController extends BladeController {
if (userId == null || userId <= 0) {
return R.fail("请先登录");
}
log.info("=== 提交选手 === userId: {}, playerName: {}", userId, athlete.getPlayerName());
if (athlete.getId() == null) {
if (athlete.getId() != null) {
MartialAthlete existing = athleteService.getById(athlete.getId());
if (existing == null) {
return R.fail("选手不存在");
}
if (!isAdminUser() && !userId.equals(existing.getCreateUser())) {
return R.fail("无权限修改该选手");
}
athlete.setCreateUser(existing.getCreateUser());
} else {
athlete.setCreateUser(userId);
}
log.info("=== 提交选手 === userId: {}, playerName: {}", userId, athlete.getPlayerName());
athlete.setUpdateUser(userId);
return R.status(athleteService.saveOrUpdate(athlete));
}
@@ -118,7 +147,21 @@ public class MartialAthleteController extends BladeController {
if (userId == null || userId <= 0) {
return R.fail("请先登录");
}
return R.status(athleteService.removeByIds(Func.toLongList(ids)));
List<Long> idList = Func.toLongList(ids);
if (idList.isEmpty()) {
return R.fail("请选择要删除的选手");
}
if (!isAdminUser()) {
long ownCount = athleteService.lambdaQuery()
.in(MartialAthlete::getId, idList)
.eq(MartialAthlete::getCreateUser, userId)
.eq(MartialAthlete::getIsDeleted, 0)
.count();
if (ownCount != idList.size()) {
return R.fail("仅可删除自己的选手");
}
}
return R.status(athleteService.removeByIds(idList));
}
/**
@@ -131,6 +174,9 @@ public class MartialAthleteController extends BladeController {
if (userId == null || userId <= 0) {
return R.fail("请先登录");
}
if (!isAdminUser()) {
return R.fail("无权限操作");
}
athleteService.checkIn(athleteId, scheduleId);
return R.success("签到成功");
}
@@ -145,6 +191,9 @@ public class MartialAthleteController extends BladeController {
if (userId == null || userId <= 0) {
return R.fail("请先登录");
}
if (!isAdminUser()) {
return R.fail("无权限操作");
}
athleteService.completePerformance(athleteId, scheduleId);
return R.success("已标记完成");
}
@@ -159,6 +208,9 @@ public class MartialAthleteController extends BladeController {
if (userId == null || userId <= 0) {
return R.fail("请先登录");
}
if (!isAdminUser()) {
return R.fail("无权限操作");
}
athleteService.updateCompetitionStatus(athleteId, status);
return R.success("状态更新成功");
}
@@ -171,17 +223,26 @@ public class MartialAthleteController extends BladeController {
public R<List<MartialAthlete>> getRegisteredAthletes(
@RequestParam Long competitionId,
@RequestParam(required = false) String projectIds) {
Long userId = AuthUtil.getUserId();
if (userId == null || userId <= 0) {
return R.fail("请先登录");
}
LambdaQueryWrapper<MartialAthlete> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(MartialAthlete::getCompetitionId, competitionId)
.eq(MartialAthlete::getIsDeleted, 0)
.eq(MartialAthlete::getRegistrationStatus, 1);
if (!isAdminUser()) {
wrapper.eq(MartialAthlete::getCreateUser, userId);
}
if (Func.isNotBlank(projectIds)) {
wrapper.in(MartialAthlete::getProjectId, Func.toLongList(projectIds));
}
List<MartialAthlete> list = athleteService.list(wrapper);
return R.data(list);
}
private boolean isAdminUser() {
return AuthUtil.isAdmin() || AuthUtil.isAdministrator();
}
}
@@ -14,6 +14,8 @@ import org.springblade.modules.martial.pojo.entity.MartialContact;
import org.springblade.modules.martial.service.IMartialContactService;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Slf4j
@RestController
@AllArgsConstructor
@@ -41,7 +43,15 @@ public class MartialContactController extends BladeController {
if (userId == null || userId <= 0) {
return R.fail("请先登录");
}
return R.data(contactService.getContactDetail(id));
MartialContact contact = contactService.lambdaQuery()
.eq(MartialContact::getId, id)
.eq(MartialContact::getCreateUser, userId)
.eq(MartialContact::getIsDeleted, 0)
.one();
if (contact == null) {
return R.fail("联系人不存在或无权限访问");
}
return R.data(contact);
}
@PostMapping("/submit")
@@ -51,6 +61,21 @@ public class MartialContactController extends BladeController {
if (userId == null || userId <= 0) {
return R.fail("请先登录");
}
if (contact.getId() != null) {
MartialContact existing = contactService.lambdaQuery()
.eq(MartialContact::getId, contact.getId())
.eq(MartialContact::getCreateUser, userId)
.eq(MartialContact::getIsDeleted, 0)
.one();
if (existing == null) {
return R.fail("联系人不存在或无权限修改");
}
contact.setCreateUser(existing.getCreateUser());
} else {
contact.setCreateUser(userId);
}
log.info("Contact submit - id: {}, name: {}, userId: {}, isDefault: {}",
contact.getId(), contact.getName(), userId, contact.getIsDefault());
@@ -64,7 +89,19 @@ public class MartialContactController extends BladeController {
if (userId == null || userId <= 0) {
return R.fail("请先登录");
}
return R.data(contactService.removeByIds(Func.toLongList(ids)));
List<Long> idList = Func.toLongList(ids);
if (idList.isEmpty()) {
return R.fail("请选择要删除的联系人");
}
long ownCount = contactService.lambdaQuery()
.in(MartialContact::getId, idList)
.eq(MartialContact::getCreateUser, userId)
.eq(MartialContact::getIsDeleted, 0)
.count();
if (ownCount != idList.size()) {
return R.fail("仅可删除自己的联系人");
}
return R.data(contactService.removeByIds(idList));
}
}
@@ -488,11 +488,27 @@ public class MartialRegistrationOrderController extends BladeController {
return R.data(order);
}
@PreAuth(RoleConstant.HAS_ROLE_USER)
@PostMapping("/remove")
@Operation(summary = "删除", description = "传入ID")
public R remove(@RequestParam String ids) {
return R.status(registrationOrderService.removeByIds(Func.toLongList(ids)));
Long userId = AuthUtil.getUserId();
if (userId == null || userId <= 0) {
return R.fail("请先登录");
}
List<Long> idList = Func.toLongList(ids);
if (idList.isEmpty()) {
return R.fail("请选择要删除的订单");
}
long ownCount = registrationOrderService.lambdaQuery()
.in(MartialRegistrationOrder::getId, idList)
.eq(MartialRegistrationOrder::getUserId, userId)
.count();
if (ownCount != idList.size()) {
return R.fail("仅可删除自己的订单");
}
return R.status(registrationOrderService.removeByIds(idList));
}
}
@@ -43,6 +43,14 @@ public class MartialTeamController extends BladeController {
if (userId == null || userId <= 0) {
return R.fail("请先登录");
}
MartialTeam team = teamService.lambdaQuery()
.eq(MartialTeam::getId, id)
.eq(MartialTeam::getCreateUser, userId)
.eq(MartialTeam::getIsDeleted, 0)
.one();
if (team == null) {
return R.fail("集体不存在或无权限访问");
}
return R.data(teamService.getTeamDetail(id));
}
@@ -61,7 +69,22 @@ public class MartialTeamController extends BladeController {
boolean result;
if (StringUtil.isNotBlank(dto.getTeamId())) {
Long teamId = Long.parseLong(dto.getTeamId());
Long teamId;
try {
teamId = Long.parseLong(dto.getTeamId());
} catch (NumberFormatException e) {
return R.fail("集体ID格式错误");
}
MartialTeam existing = teamService.lambdaQuery()
.eq(MartialTeam::getId, teamId)
.eq(MartialTeam::getCreateUser, userId)
.eq(MartialTeam::getIsDeleted, 0)
.one();
if (existing == null) {
return R.fail("集体不存在或无权限修改");
}
team.setId(teamId);
log.info("Updating team with id: {}", teamId);
result = teamService.updateTeamWithMembers(team, dto.getMemberIds());
@@ -79,6 +102,14 @@ public class MartialTeamController extends BladeController {
if (userId == null || userId <= 0) {
return R.fail("请先登录");
}
MartialTeam team = teamService.lambdaQuery()
.eq(MartialTeam::getId, id)
.eq(MartialTeam::getCreateUser, userId)
.eq(MartialTeam::getIsDeleted, 0)
.one();
if (team == null) {
return R.fail("集体不存在或无权限删除");
}
return R.data(teamService.removeTeamWithMembers(id));
}
@@ -48,23 +48,26 @@ public class MartialContactServiceImpl extends ServiceImpl<MartialContactMapper,
updateWrapper.eq(MartialContact::getCreateUser, userId)
.eq(MartialContact::getIsDeleted, 0)
.set(MartialContact::getIsDefault, false);
// Exclude current contact if it's an update
// Exclude current contact if it is an update
if (contact.getId() != null) {
updateWrapper.ne(MartialContact::getId, contact.getId());
}
this.update(updateWrapper);
log.info("Cleared default status for user {}'s other contacts", userId);
log.info("Cleared default status for user {} contacts", userId);
}
// Set audit fields
Date now = new Date();
if (contact.getId() == null) {
contact.setCreateUser(userId);
contact.setCreateTime(new Date());
}
contact.setCreateTime(now);
contact.setUpdateUser(userId);
contact.setUpdateTime(new Date());
contact.setUpdateTime(now);
return this.save(contact);
}
return this.saveOrUpdate(contact);
contact.setUpdateUser(userId);
contact.setUpdateTime(now);
return this.updateById(contact);
}
}
@@ -5,6 +5,8 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.modules.martial.mapper.MartialTeamMapper;
import org.springblade.modules.martial.mapper.MartialTeamMemberMapper;
import org.springblade.modules.martial.pojo.entity.MartialAthlete;
@@ -16,7 +18,6 @@ import org.springblade.modules.martial.service.IMartialTeamService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springblade.core.secure.utils.AuthUtil;
import java.time.LocalDateTime;
import java.util.ArrayList;
@@ -34,8 +35,14 @@ public class MartialTeamServiceImpl extends ServiceImpl<MartialTeamMapper, Marti
@Override
@Transactional(rollbackFor = Exception.class)
public boolean saveTeamWithMembers(MartialTeam team, List<Long> memberIds) {
Long userId = AuthUtil.getUserId();
if (userId == null || userId <= 0) {
throw new ServiceException("请先登录");
}
validateMemberOwnership(memberIds, userId);
team.setMemberCount(memberIds != null ? memberIds.size() : 0);
team.setCreateUser(AuthUtil.getUserId());
team.setCreateUser(userId);
boolean saved = this.save(team);
if (saved && memberIds != null && !memberIds.isEmpty()) {
@@ -56,8 +63,21 @@ public class MartialTeamServiceImpl extends ServiceImpl<MartialTeamMapper, Marti
@Override
@Transactional(rollbackFor = Exception.class)
public boolean updateTeamWithMembers(MartialTeam team, List<Long> memberIds) {
Long userId = AuthUtil.getUserId();
if (userId == null || userId <= 0) {
throw new ServiceException("请先登录");
}
MartialTeam existing = this.getById(team.getId());
if (existing == null || existing.getIsDeleted() != null && existing.getIsDeleted() == 1) {
throw new ServiceException("集体不存在");
}
if (!AuthUtil.isAdmin() && !AuthUtil.isAdministrator() && !userId.equals(existing.getCreateUser())) {
throw new ServiceException("无权限修改该集体");
}
validateMemberOwnership(memberIds, userId);
team.setMemberCount(memberIds != null ? memberIds.size() : 0);
team.setUpdateUser(AuthUtil.getUserId());
team.setUpdateUser(userId);
boolean updated = this.updateById(team);
if (updated) {
@@ -198,4 +218,19 @@ public class MartialTeamServiceImpl extends ServiceImpl<MartialTeamMapper, Marti
return this.removeById(id);
}
private void validateMemberOwnership(List<Long> memberIds, Long userId) {
if (memberIds == null || memberIds.isEmpty()) {
return;
}
List<Long> distinctIds = memberIds.stream().distinct().collect(Collectors.toList());
long ownCount = athleteService.lambdaQuery()
.in(MartialAthlete::getId, distinctIds)
.eq(MartialAthlete::getCreateUser, userId)
.eq(MartialAthlete::getIsDeleted, 0)
.count();
if (ownCount != distinctIds.size()) {
throw new ServiceException("成员包含非本人选手");
}
}
}