标准角色只允许管理员进行修改菜单权限与数据权限

This commit is contained in:
陈博文
2025-06-23 16:52:35 +08:00
parent 2046384ca0
commit 84ddc8ca6e
6 changed files with 64 additions and 4 deletions

View File

@@ -34,6 +34,8 @@ public interface ErrorCodeConstants {
ErrorCode ROLE_IS_DISABLE = new ErrorCode(1_002_002_004, "名字为【{}】的角色已被禁用"); ErrorCode ROLE_IS_DISABLE = new ErrorCode(1_002_002_004, "名字为【{}】的角色已被禁用");
ErrorCode ROLE_ADMIN_CODE_ERROR = new ErrorCode(1_002_002_005, "标识【{}】不能使用"); ErrorCode ROLE_ADMIN_CODE_ERROR = new ErrorCode(1_002_002_005, "标识【{}】不能使用");
ErrorCode ROLE_CAN_NOT_UPDATE_NORMAL_TYPE_ROLE = new ErrorCode(1_002_002_006, "不能操作类型为标准的角色,除非是管理员角色");
// ========== 用户模块 1-002-003-000 ========== // ========== 用户模块 1-002-003-000 ==========
ErrorCode USER_USERNAME_EXISTS = new ErrorCode(1_002_003_000, "用户账号已经存在"); ErrorCode USER_USERNAME_EXISTS = new ErrorCode(1_002_003_000, "用户账号已经存在");
ErrorCode USER_MOBILE_EXISTS = new ErrorCode(1_002_003_001, "手机号已经存在"); ErrorCode USER_MOBILE_EXISTS = new ErrorCode(1_002_003_001, "手机号已经存在");

View File

@@ -3,6 +3,10 @@ package cn.iocoder.yudao.module.system.enums.permission;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
/**
* @author chenbowen
*/
@Getter @Getter
@AllArgsConstructor @AllArgsConstructor
public enum RoleTypeEnum { public enum RoleTypeEnum {
@@ -11,11 +15,16 @@ public enum RoleTypeEnum {
* 内置角色 * 内置角色
*/ */
SYSTEM(1), SYSTEM(1),
/**
* 标准角色
*/
NORMAL(2),
/** /**
* 自定义角色 * 自定义角色
*/ */
CUSTOM(2); CUSTOM(3);
private final Integer type; private final Integer type;
} }

View File

@@ -16,6 +16,7 @@ import cn.iocoder.yudao.module.system.dal.mysql.permission.RoleMenuMapper;
import cn.iocoder.yudao.module.system.dal.mysql.permission.UserRoleMapper; import cn.iocoder.yudao.module.system.dal.mysql.permission.UserRoleMapper;
import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants; import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants;
import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum; import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum;
import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum;
import cn.iocoder.yudao.module.system.service.dept.DeptService; import cn.iocoder.yudao.module.system.service.dept.DeptService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService; import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import com.baomidou.dynamic.datasource.annotation.DSTransactional; import com.baomidou.dynamic.datasource.annotation.DSTransactional;
@@ -24,6 +25,7 @@ import com.google.common.base.Suppliers;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching; import org.springframework.cache.annotation.Caching;
@@ -33,8 +35,11 @@ import org.springframework.transaction.annotation.Transactional;
import java.util.*; import java.util.*;
import java.util.function.Supplier; import java.util.function.Supplier;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.ROLE_CAN_NOT_UPDATE_SYSTEM_TYPE_ROLE;
/** /**
* 权限 Service 实现类 * 权限 Service 实现类
@@ -58,6 +63,8 @@ public class PermissionServiceImpl implements PermissionService {
private DeptService deptService; private DeptService deptService;
@Resource @Resource
private AdminUserService userService; private AdminUserService userService;
@Autowired
private PermissionService permissionService;
@Override @Override
public boolean hasAnyPermissions(Long userId, String... permissions) { public boolean hasAnyPermissions(Long userId, String... permissions) {
@@ -139,6 +146,12 @@ public class PermissionServiceImpl implements PermissionService {
allEntries = true) // allEntries 清空所有缓存,主要一次更新涉及到的 menuIds 较多,反倒批量会更快 allEntries = true) // allEntries 清空所有缓存,主要一次更新涉及到的 menuIds 较多,反倒批量会更快
}) })
public void assignRoleMenu(Long roleId, Set<Long> menuIds) { public void assignRoleMenu(Long roleId, Set<Long> menuIds) {
RoleDO role = roleService.getRole(roleId);
Set<Long> userRoleIdListByUserId = permissionService.getUserRoleIdListByUserId(getLoginUserId());
// 如果为标准角色,只允许管理员修改菜单权限
if (RoleTypeEnum.NORMAL.getType().equals(role.getType()) && !roleService.hasAnySuperAdmin(userRoleIdListByUserId)) {
throw exception(ROLE_CAN_NOT_UPDATE_SYSTEM_TYPE_ROLE);
}
// 获得角色拥有菜单编号 // 获得角色拥有菜单编号
Set<Long> dbMenuIds = convertSet(roleMenuMapper.selectListByRoleId(roleId), RoleMenuDO::getMenuId); Set<Long> dbMenuIds = convertSet(roleMenuMapper.selectListByRoleId(roleId), RoleMenuDO::getMenuId);
// 计算新增和删除的菜单编号 // 计算新增和删除的菜单编号
@@ -269,6 +282,12 @@ public class PermissionServiceImpl implements PermissionService {
@Override @Override
public void assignRoleDataScope(Long roleId, Integer dataScope, Set<Long> dataScopeDeptIds) { public void assignRoleDataScope(Long roleId, Integer dataScope, Set<Long> dataScopeDeptIds) {
RoleDO role = roleService.getRole(roleId);
Set<Long> userRoleIdListByUserId = permissionService.getUserRoleIdListByUserId(getLoginUserId());
// 如果为标准角色,只允许管理员修改数据权限
if (RoleTypeEnum.NORMAL.getType().equals(role.getType()) && !roleService.hasAnySuperAdmin(userRoleIdListByUserId)) {
throw exception(ROLE_CAN_NOT_UPDATE_SYSTEM_TYPE_ROLE);
}
roleService.updateRoleDataScope(roleId, dataScope, dataScopeDeptIds); roleService.updateRoleDataScope(roleId, dataScope, dataScopeDeptIds);
} }

View File

@@ -169,6 +169,11 @@ public class RoleServiceImpl implements RoleService {
if (RoleTypeEnum.SYSTEM.getType().equals(role.getType())) { if (RoleTypeEnum.SYSTEM.getType().equals(role.getType())) {
throw exception(ROLE_CAN_NOT_UPDATE_SYSTEM_TYPE_ROLE); throw exception(ROLE_CAN_NOT_UPDATE_SYSTEM_TYPE_ROLE);
} }
// 标准角色非管理员不允许修改
if (RoleTypeEnum.NORMAL.getType().equals(role.getType())
&& !RoleCodeEnum.isSuperAdmin(role.getCode())) {
throw exception(ROLE_CAN_NOT_UPDATE_NORMAL_TYPE_ROLE);
}
return role; return role;
} }

View File

@@ -1,10 +1,13 @@
package cn.iocoder.yudao.module.system.service.permission; package cn.iocoder.yudao.module.system.service.permission;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleMenuDO; import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleMenuDO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.UserRoleDO; import cn.iocoder.yudao.module.system.dal.dataobject.permission.UserRoleDO;
import cn.iocoder.yudao.module.system.dal.mysql.permission.RoleMapper;
import cn.iocoder.yudao.module.system.dal.mysql.permission.RoleMenuMapper; import cn.iocoder.yudao.module.system.dal.mysql.permission.RoleMenuMapper;
import cn.iocoder.yudao.module.system.dal.mysql.permission.UserRoleMapper; import cn.iocoder.yudao.module.system.dal.mysql.permission.UserRoleMapper;
import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum;
import cn.iocoder.yudao.module.system.service.dept.DeptService; import cn.iocoder.yudao.module.system.service.dept.DeptService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService; import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
@@ -33,6 +36,8 @@ public class PermissionServiceTest extends BaseDbUnitTest {
@Resource @Resource
private UserRoleMapper userRoleMapper; private UserRoleMapper userRoleMapper;
@Resource
private RoleMapper roleMapper;
@Resource @Resource
private RoleServiceImpl roleService; private RoleServiceImpl roleService;
@MockBean @MockBean
@@ -47,7 +52,8 @@ public class PermissionServiceTest extends BaseDbUnitTest {
@Test @Test
public void testAssignRoleMenu() { public void testAssignRoleMenu() {
// 准备参数 // 准备参数
Long roleId = 1L; RoleDO role = randomPojo(RoleDO.class, o -> o.setType(RoleTypeEnum.CUSTOM.getType()).setId(1L).setTenantId(0L));
roleMapper.insert(role);
Set<Long> menuIds = asSet(200L, 300L); Set<Long> menuIds = asSet(200L, 300L);
// mock 数据 // mock 数据
RoleMenuDO roleMenu01 = randomPojo(RoleMenuDO.class).setRoleId(1L).setMenuId(100L); RoleMenuDO roleMenu01 = randomPojo(RoleMenuDO.class).setRoleId(1L).setMenuId(100L);
@@ -58,7 +64,7 @@ public class PermissionServiceTest extends BaseDbUnitTest {
roleMenuMapper.insert(roleMenu02); roleMenuMapper.insert(roleMenu02);
// 调用 // 调用
permissionService.assignRoleMenu(roleId, menuIds); permissionService.assignRoleMenu(role.getId(), menuIds);
// 断言 // 断言
List<RoleMenuDO> roleMenuList = roleMenuMapper.selectList(); List<RoleMenuDO> roleMenuList = roleMenuMapper.selectList();
assertEquals(2, roleMenuList.size()); assertEquals(2, roleMenuList.size());

View File

@@ -151,7 +151,7 @@ public class RoleServiceImplTest extends BaseDbUnitTest {
@Test @Test
public void testValidateUpdateRole_success() { public void testValidateUpdateRole_success() {
RoleDO roleDO = randomPojo(RoleDO.class); RoleDO roleDO = randomPojo(RoleDO.class);
roleMapper.insert(roleDO); roleMapper.insert(roleDO.setType(RoleTypeEnum.CUSTOM.getType()));
// 准备参数 // 准备参数
Long id = roleDO.getId(); Long id = roleDO.getId();
@@ -159,6 +159,25 @@ public class RoleServiceImplTest extends BaseDbUnitTest {
roleService.validateRoleForUpdate(id); roleService.validateRoleForUpdate(id);
} }
@Test
public void testValidateUpdateRole_fail() {
RoleDO roleDO = randomPojo(RoleDO.class);
roleMapper.insert(roleDO.setType(RoleTypeEnum.SYSTEM.getType()));
// 准备参数
Long systemRoleId = roleDO.getId();
RoleDO normalRoleDO = randomPojo(RoleDO.class);
roleMapper.insert(normalRoleDO.setType(RoleTypeEnum.NORMAL.getType()));
// 准备参数
Long normalRoleId = normalRoleDO.getId();
// 调用,并断言异常
assertServiceException(() -> roleService.validateRoleForUpdate(normalRoleId),
ROLE_CAN_NOT_UPDATE_NORMAL_TYPE_ROLE);
assertServiceException(() -> roleService.validateRoleForUpdate(systemRoleId),
ROLE_CAN_NOT_UPDATE_SYSTEM_TYPE_ROLE);
}
@Test @Test
public void testValidateUpdateRole_roleIdNotExist() { public void testValidateUpdateRole_roleIdNotExist() {
assertServiceException(() -> roleService.validateRoleForUpdate(randomLongId()), ROLE_NOT_EXISTS); assertServiceException(() -> roleService.validateRoleForUpdate(randomLongId()), ROLE_NOT_EXISTS);