fix: RBAC模型P2安全修复

P2-8: 删除实体时级联清理中间表
P2-9: BaseEntity添加delFlag逻辑删除字段
P2-10: adminLogout清理roleIds和perms缓存
P2-11: 启用EnableMethodSecurity,BaseController增加checkPermission钩子
P2-12: 移除eps/getModuleTree/createCode的TokenIgnore
This commit is contained in:
OpenCode
2026-07-17 21:06:32 +08:00
parent e02c7a02dc
commit 37df40f5e4
13 changed files with 78 additions and 5 deletions
@@ -115,6 +115,7 @@ public abstract class BaseController<S extends BaseService<T>, T extends BaseEnt
@Operation(summary = "新增", description = "新增信息,对应后端的实体类")
@PostMapping("/add")
protected R add(@RequestAttribute() JSONObject requestParams) {
checkPermission("add");
String body = requestParams.getStr("body");
if (JSONUtil.isTypeJSONArray(body)) {
JSONArray array = JSONUtil.parseArray(body);
@@ -135,6 +136,7 @@ public abstract class BaseController<S extends BaseService<T>, T extends BaseEnt
@PostMapping("/delete")
protected R delete(HttpServletRequest request, @RequestBody Map<String, Object> params,
@RequestAttribute() JSONObject requestParams) {
checkPermission("delete");
service.delete(requestParams, Convert.toLongArray(getIds(params)));
return R.ok();
}
@@ -147,6 +149,7 @@ public abstract class BaseController<S extends BaseService<T>, T extends BaseEnt
@Operation(summary = "修改", description = "根据ID修改")
@PostMapping("/update")
protected R update(@RequestBody T t, @RequestAttribute() JSONObject requestParams) {
checkPermission("update");
Long id = t.getId();
JSONObject info = JSONUtil.parseObj(JSONUtil.toJsonStr(service.getById(id)));
requestParams.forEach(info::set);
@@ -286,4 +289,7 @@ public abstract class BaseController<S extends BaseService<T>, T extends BaseEnt
page.setRecords(transformList(page.getRecords(), asType));
return page;
}
protected void checkPermission(String action) {
}
}
@@ -31,6 +31,10 @@ public abstract class BaseEntity<T extends Model<T>> extends Model<T> implements
@ColumnDefine(comment = "更新时间")
protected Date updateTime;
@Column(isLogicDelete = true)
@ColumnDefine(comment = "删除标记 0:未删除 1:已删除", defaultValue = "0")
protected Integer delFlag;
@Ignore
@Column(ignore = true)
@JsonIgnore
@@ -15,6 +15,7 @@ import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
@@ -32,6 +33,7 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl
import org.springframework.web.util.pattern.PathPattern;
@EnableWebSecurity
@EnableMethodSecurity
@Configuration
@Slf4j
@RequiredArgsConstructor
@@ -85,7 +85,8 @@ public class CoolSecurityUtil {
*/
public static void adminLogout(Long adminUserId, String username) {
coolCache.del("admin:department:" + adminUserId, "admin:passwordVersion:" + adminUserId,
"admin:userInfo:" + adminUserId, "admin:userDetails:" + username);
"admin:userInfo:" + adminUserId, "admin:userDetails:" + username,
"admin:roleIds:" + adminUserId, "admin:perms:" + adminUserId);
}
/**
@@ -24,14 +24,12 @@ public class AdminBaseCodingController {
private final BaseCodingService baseCodingService;
@TokenIgnore
@Operation(summary = "获取模块目录结构", description = "获取模块目录结构")
@GetMapping("/getModuleTree")
public R getModuleTree() {
return R.ok(baseCodingService.getModuleTree());
}
@TokenIgnore
@Operation(summary = "创建代码", description = "创建代码")
@PostMapping("/createCode")
public R createCode(@RequestAttribute JSONObject requestParams) {
@@ -44,7 +44,6 @@ public class AdminBaseCommController {
final private FileUploadStrategyFactory fileUploadStrategyFactory;
@TokenIgnore
@Operation(summary = "实体信息与路径", description = "系统所有的实体信息与路径,供前端自动生成代码与服务")
@GetMapping("/eps")
public R eps() {
@@ -4,10 +4,12 @@ import cn.hutool.json.JSONObject;
import com.cool.core.annotation.CoolRestController;
import com.cool.core.base.BaseController;
import com.cool.core.request.R;
import com.cool.core.util.CoolSecurityUtil;
import com.cool.modules.base.entity.sys.BaseSysDepartmentEntity;
import com.cool.modules.base.service.sys.BaseSysDepartmentService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@@ -22,6 +24,13 @@ import java.util.List;
public class AdminBaseSysDepartmentController
extends BaseController<BaseSysDepartmentService, BaseSysDepartmentEntity> {
@Override
protected void checkPermission(String action) {
if (("add".equals(action) || "delete".equals(action) || "update".equals(action)) && !CoolSecurityUtil.isSuperAdmin()) {
throw new AccessDeniedException("仅超级管理员可操作部门");
}
}
@Override
protected void init(HttpServletRequest request, JSONObject requestParams) {
}
@@ -12,6 +12,7 @@ import com.cool.modules.base.service.sys.BaseSysRoleService;
import com.mybatisflex.core.query.QueryWrapper;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.security.access.AccessDeniedException;
/**
* 系统角色
@@ -20,6 +21,15 @@ import jakarta.servlet.http.HttpServletRequest;
@CoolRestController(api = { "add", "delete", "update", "page", "list", "info" })
public class AdminBaseSysRoleController extends BaseController<BaseSysRoleService, BaseSysRoleEntity> {
@Override
protected void checkPermission(String action) {
if ("add".equals(action) || "delete".equals(action) || "update".equals(action)) {
if (!CoolSecurityUtil.isSuperAdmin()) {
throw new AccessDeniedException("仅超级管理员可操作角色");
}
}
}
@Override
protected void init(HttpServletRequest request, JSONObject requestParams) {
JSONObject tokenInfo = requestParams.getJSONObject("tokenInfo");
@@ -8,9 +8,11 @@ import com.cool.modules.base.entity.sys.BaseSysUserEntity;
import com.cool.modules.base.service.sys.BaseSysUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestAttribute;
import com.cool.core.util.CoolSecurityUtil;
import jakarta.servlet.http.HttpServletRequest;
/**
@@ -20,6 +22,13 @@ import jakarta.servlet.http.HttpServletRequest;
@CoolRestController(api = { "add", "delete", "update", "page", "info" })
public class AdminBaseSysUserController extends BaseController<BaseSysUserService, BaseSysUserEntity> {
@Override
protected void checkPermission(String action) {
if ("delete".equals(action) && !CoolSecurityUtil.isSuperAdmin()) {
throw new AccessDeniedException("仅超级管理员可删除用户");
}
}
@Override
protected void init(HttpServletRequest request, JSONObject requestParams) {
}
@@ -5,8 +5,10 @@ import com.cool.core.base.BaseServiceImpl;
import com.cool.core.exception.CoolPreconditions;
import com.cool.core.util.CoolSecurityUtil;
import com.cool.modules.base.entity.sys.BaseSysDepartmentEntity;
import com.cool.modules.base.entity.sys.BaseSysRoleDepartmentEntity;
import com.cool.modules.base.entity.sys.BaseSysUserEntity;
import com.cool.modules.base.mapper.sys.BaseSysDepartmentMapper;
import com.cool.modules.base.mapper.sys.BaseSysRoleDepartmentMapper;
import com.cool.modules.base.mapper.sys.BaseSysUserMapper;
import com.cool.modules.base.service.sys.BaseSysDepartmentService;
import com.cool.modules.base.service.sys.BaseSysPermsService;
@@ -16,6 +18,7 @@ import java.util.ArrayList;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* 系统部门
@@ -30,6 +33,8 @@ public class BaseSysDepartmentServiceImpl extends
final private BaseSysPermsService baseSysPermsService;
final private BaseSysRoleDepartmentMapper baseSysRoleDepartmentMapper;
@Override
public void order(List<BaseSysDepartmentEntity> list) {
list.forEach(baseSysDepartmentEntity -> {
@@ -64,6 +69,7 @@ public class BaseSysDepartmentServiceImpl extends
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean delete(JSONObject requestParams, Long... ids) {
List<Long> allDeptIds = new ArrayList<>(List.of(ids));
for (Long id : ids) {
@@ -72,6 +78,8 @@ public class BaseSysDepartmentServiceImpl extends
long userCount = baseSysUserMapper.selectCountByQuery(
QueryWrapper.create().in(BaseSysUserEntity::getDepartmentId, allDeptIds));
CoolPreconditions.check(userCount > 0, "该部门或其子部门下存在用户,无法删除");
baseSysRoleDepartmentMapper.deleteByQuery(
QueryWrapper.create().in(BaseSysRoleDepartmentEntity::getDepartmentId, allDeptIds));
return super.delete(ids);
}
@@ -14,7 +14,9 @@ import com.cool.core.util.CompilerUtils;
import com.cool.core.util.CoolSecurityUtil;
import com.cool.core.util.PathUtils;
import com.cool.modules.base.entity.sys.BaseSysMenuEntity;
import com.cool.modules.base.entity.sys.BaseSysRoleMenuEntity;
import com.cool.modules.base.mapper.sys.BaseSysMenuMapper;
import com.cool.modules.base.mapper.sys.BaseSysRoleMenuMapper;
import com.cool.modules.base.service.sys.BaseSysMenuService;
import com.cool.modules.base.service.sys.BaseSysPermsService;
import com.mybatisflex.core.query.QueryWrapper;
@@ -37,6 +39,8 @@ public class BaseSysMenuServiceImpl extends BaseServiceImpl<BaseSysMenuMapper, B
final private CoolEps coolEps;
final private BaseSysRoleMenuMapper baseSysRoleMenuMapper;
@Override
public Object list(JSONObject requestParams, QueryWrapper queryWrapper) {
List<BaseSysMenuEntity> list = baseSysPermsService.getMenus(CoolSecurityUtil.getAdminUsername());
@@ -71,6 +75,10 @@ public class BaseSysMenuServiceImpl extends BaseServiceImpl<BaseSysMenuMapper, B
@Override
public boolean delete(Long... ids) {
for (Long id : ids) {
baseSysRoleMenuMapper.deleteByQuery(
QueryWrapper.create().eq(BaseSysRoleMenuEntity::getMenuId, id));
}
super.delete(ids);
for (Long id : ids) {
this.delChildMenu(id);
@@ -9,9 +9,11 @@ import com.cool.core.util.CoolSecurityUtil;
import com.cool.modules.base.entity.sys.BaseSysRoleDepartmentEntity;
import com.cool.modules.base.entity.sys.BaseSysRoleEntity;
import com.cool.modules.base.entity.sys.BaseSysRoleMenuEntity;
import com.cool.modules.base.entity.sys.BaseSysUserRoleEntity;
import com.cool.modules.base.mapper.sys.BaseSysRoleDepartmentMapper;
import com.cool.modules.base.mapper.sys.BaseSysRoleMapper;
import com.cool.modules.base.mapper.sys.BaseSysRoleMenuMapper;
import com.cool.modules.base.mapper.sys.BaseSysUserRoleMapper;
import com.cool.modules.base.service.sys.BaseSysPermsService;
import com.cool.modules.base.service.sys.BaseSysRoleService;
import com.mybatisflex.core.query.QueryWrapper;
@@ -37,6 +39,8 @@ public class BaseSysRoleServiceImpl extends BaseServiceImpl<BaseSysRoleMapper, B
final private BaseSysPermsService baseSysPermsService;
final private BaseSysUserRoleMapper baseSysUserRoleMapper;
@Override
public Object add(JSONObject requestParams, BaseSysRoleEntity entity) {
BaseSysRoleEntity checkLabel = getOne(QueryWrapper.create().eq(BaseSysRoleEntity::getLabel, entity.getLabel()));
@@ -77,6 +81,12 @@ public class BaseSysRoleServiceImpl extends BaseServiceImpl<BaseSysRoleMapper, B
if (type == ModifyEnum.DELETE) {
Long[] ids = requestParams.get("ids", Long[].class);
for (Long id : ids) {
baseSysRoleMenuMapper.deleteByQuery(
QueryWrapper.create().eq(BaseSysRoleMenuEntity::getRoleId, id));
baseSysRoleDepartmentMapper.deleteByQuery(
QueryWrapper.create().eq(BaseSysRoleDepartmentEntity::getRoleId, id));
baseSysUserRoleMapper.deleteByQuery(
QueryWrapper.create().eq(BaseSysUserRoleEntity::getRoleId, id));
baseSysPermsService.refreshPermsByRoleId(id);
}
} else {
@@ -182,7 +182,16 @@ public class BaseSysUserServiceImpl extends BaseServiceImpl<BaseSysUserMapper, B
@Override
public void modifyAfter(JSONObject requestParams, BaseSysUserEntity baseSysUserEntity,
ModifyEnum type) {
if (type != ModifyEnum.DELETE && requestParams.get("roleIdList", Long[].class) != null) {
if (type == ModifyEnum.DELETE) {
Long[] ids = requestParams.get("ids", Long[].class);
if (ids != null) {
for (Long id : ids) {
baseSysUserRoleMapper.deleteByQuery(
QueryWrapper.create().eq(BaseSysUserRoleEntity::getUserId, id));
CoolSecurityUtil.adminLogout(id, null);
}
}
} else if (requestParams.get("roleIdList", Long[].class) != null) {
Long[] roleIdList = requestParams.get("roleIdList", Long[].class);
validateRoleAssignment(roleIdList);
baseSysPermsService.updateUserRole(baseSysUserEntity.getId(), roleIdList);