feat(permission): 重构权限系统实现对象级别权限控制

- 在PermissionService中新增getScopedMenusByRoleId和getScopedPermissionsByRoleId方法
- 实现getScopedMenusByRoleId方法用于获取角色的对象范围菜单列表
- 实现getScopedPermissionsByRoleId方法用于获取角色的对象范围权限集合
- 添加getEnabledScopedRole私有方法确保只处理启用状态的角色对象
- 在ProductMemberServiceImpl中替换SystemRoleMapper为ObjectPermissionApi调用
- 将验证产品角色的方法改为调用远程权限接口验证
- 更新ProductObjectPermissionService使用远程权限接口替代本地查询
- 修改ProductServiceImpl中权限获取逻辑使用新的对象权限API
- 移除原有的系统菜单和角色相关的数据对象依赖
- 在测试类中更新模拟对象和断言逻辑适配新的权限接口调用
This commit is contained in:
2026-04-23 09:22:43 +08:00
parent 2943a6255b
commit 156728b1b9
16 changed files with 217 additions and 376 deletions

View File

@@ -1,6 +1,9 @@
package com.njcn.rdms.module.system.service.permission;
import com.njcn.rdms.module.system.dal.dataobject.permission.MenuDO;
import java.util.Collection;
import java.util.List;
import java.util.Set;
/**
@@ -81,6 +84,10 @@ public interface PermissionService {
return getRoleMenuListByRoleId(roleIds);
}
List<MenuDO> getScopedMenusByRoleId(Long roleId, String scopeType, String objectType);
Set<String> getScopedPermissionsByRoleId(Long roleId, String scopeType, String objectType);
/**
* 获得拥有指定菜单的角色编号数组,从缓存中获取
*

View File

@@ -3,6 +3,7 @@ package com.njcn.rdms.module.system.service.permission;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.njcn.rdms.framework.common.enums.CommonStatusEnum;
import com.njcn.rdms.framework.common.util.collection.CollectionUtils;
@@ -248,7 +249,9 @@ public class PermissionServiceImpl implements PermissionService {
}
// 统一按角色实际授权返回当前仍然有效的菜单,并补齐其父链
Set<Long> scopedRoleIds = convertSet(roleService.getRoleList(roleIds, scopeType, objectType), RoleDO::getId);
Set<Long> scopedRoleIds = convertSet(roleService.getRoleList(roleIds, scopeType, objectType).stream()
.filter(role -> CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus()))
.toList(), RoleDO::getId);
if (CollUtil.isEmpty(scopedRoleIds)) {
return Collections.emptySet();
}
@@ -257,6 +260,34 @@ public class PermissionServiceImpl implements PermissionService {
return expandMenuIdsWithAncestors(convertSet(menus, MenuDO::getId), scopeType, objectType);
}
@Override
public List<MenuDO> getScopedMenusByRoleId(Long roleId, String scopeType, String objectType) {
RoleDO role = getEnabledScopedRole(roleId, scopeType, objectType);
if (role == null) {
return Collections.emptyList();
}
Set<Long> menuIds = getRoleMenuListByRoleId(Collections.singleton(roleId), scopeType, objectType);
if (CollUtil.isEmpty(menuIds)) {
return Collections.emptyList();
}
return menuService.filterDisableMenus(menuService.getMenuList(menuIds, scopeType, objectType));
}
@Override
public Set<String> getScopedPermissionsByRoleId(Long roleId, String scopeType, String objectType) {
List<MenuDO> menus = getScopedMenusByRoleId(roleId, scopeType, objectType);
if (CollUtil.isEmpty(menus)) {
return Collections.emptySet();
}
Set<String> permissions = new LinkedHashSet<>();
menus.forEach(menu -> {
if (StrUtil.isNotBlank(menu.getPermission())) {
permissions.add(menu.getPermission());
}
});
return permissions;
}
@Override
@Cacheable(value = RedisKeyConstants.MENU_ROLE_ID_LIST, key = "#menuId")
public Set<Long> getMenuRoleIdListByMenuIdFromCache(Long menuId) {
@@ -357,6 +388,18 @@ public class PermissionServiceImpl implements PermissionService {
return role;
}
/**
* scoped 权限查询只消费当前仍然有效的对象角色;缺失、作用域不匹配或已禁用时都返回 null
* 由上层统一收口为空菜单/空权限结果。
*/
private RoleDO getEnabledScopedRole(Long roleId, String scopeType, String objectType) {
RoleDO role = roleService.getRole(roleId, scopeType, objectType);
if (role == null || !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())) {
return null;
}
return role;
}
private PermissionServiceImpl getSelf() {
return SpringUtil.getBean(getClass());
}

View File

@@ -54,6 +54,10 @@ public interface RoleService {
*/
RoleDO getRole(Long id);
RoleDO getRole(Long roleId, String scopeType, String objectType);
RoleDO getRoleByCode(String code, String scopeType, String objectType);
/**
* 获得角色,从缓存中
*

View File

@@ -208,6 +208,17 @@ public class RoleServiceImpl implements RoleService {
return roleMapper.selectById(id);
}
@Override
public RoleDO getRole(Long roleId, String scopeType, String objectType) {
RoleDO role = roleMapper.selectById(roleId);
return matchesScope(role, scopeType, objectType) ? role : null;
}
@Override
public RoleDO getRoleByCode(String code, String scopeType, String objectType) {
return roleMapper.selectByCode(code, scopeType, objectType);
}
@Override
@Cacheable(value = RedisKeyConstants.ROLE, key = "#id", unless = "#result == null")
public RoleDO getRoleFromCache(Long id) {