feat(permission): 新增对象权限API接口及实现

- 定义ObjectPermissionApi接口提供对象作用域权限查询功能
- 实现ObjectPermissionApiImpl提供角色权限查询和转换逻辑
- 添加ObjectMenuRespDTO、ObjectRoleRespDTO和ObjectRolePermissionRespDTO数据传输对象
- 实现按角色ID、角色编码查询对象作用域角色及权限的功能
- 提供获取对象作用域角色菜单与权限聚合结果的方法
- 添加完整单元测试覆盖对象权限API的主要业务场景
This commit is contained in:
2026-04-23 09:23:33 +08:00
parent 156728b1b9
commit 0a6d70f7cf
7 changed files with 924 additions and 0 deletions

View File

@@ -0,0 +1,89 @@
package com.njcn.rdms.module.system.api.permission;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.util.collection.CollectionUtils;
import com.njcn.rdms.module.system.api.permission.dto.ObjectRolePermissionRespDTO;
import com.njcn.rdms.module.system.api.permission.dto.ObjectRoleRespDTO;
import com.njcn.rdms.module.system.enums.ApiConstants;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
@FeignClient(name = ApiConstants.NAME)
@Tag(name = "RPC 服务 - 对象权限")
public interface ObjectPermissionApi {
String PREFIX = ApiConstants.PREFIX + "/permission/object";
@GetMapping(PREFIX + "/role-by-id")
@Operation(summary = "按角色 ID 查询对象作用域角色摘要")
@Parameter(name = "roleId", description = "角色 ID", example = "1024", required = true)
@Parameter(name = "scopeType", description = "权限作用域类型", example = "object", required = true)
@Parameter(name = "objectType", description = "对象类型", example = "product", required = true)
CommonResult<ObjectRoleRespDTO> getObjectRoleById(@RequestParam("roleId") Long roleId,
@RequestParam("scopeType") String scopeType,
@RequestParam("objectType") String objectType);
@GetMapping(PREFIX + "/role-by-code")
@Operation(summary = "按角色编码查询对象作用域角色摘要")
@Parameter(name = "roleCode", description = "角色编码", example = "product_manager", required = true)
@Parameter(name = "scopeType", description = "权限作用域类型", example = "object", required = true)
@Parameter(name = "objectType", description = "对象类型", example = "product", required = true)
CommonResult<ObjectRoleRespDTO> getObjectRoleByCode(@RequestParam("roleCode") String roleCode,
@RequestParam("scopeType") String scopeType,
@RequestParam("objectType") String objectType);
@GetMapping(PREFIX + "/role-list")
@Operation(summary = "按角色 ID 批量查询对象作用域角色摘要")
@Parameter(name = "roleIds", description = "角色 ID 集合", example = "1,2", required = true)
@Parameter(name = "scopeType", description = "权限作用域类型", example = "object", required = true)
@Parameter(name = "objectType", description = "对象类型", example = "product", required = true)
CommonResult<List<ObjectRoleRespDTO>> getObjectRoleList(@RequestParam("roleIds") Collection<Long> roleIds,
@RequestParam("scopeType") String scopeType,
@RequestParam("objectType") String objectType);
@GetMapping(PREFIX + "/permissions")
@Operation(summary = "查询对象作用域角色权限集合")
@Parameter(name = "roleId", description = "角色 ID", example = "1024", required = true)
@Parameter(name = "scopeType", description = "权限作用域类型", example = "object", required = true)
@Parameter(name = "objectType", description = "对象类型", example = "product", required = true)
CommonResult<Set<String>> getObjectRolePermissions(@RequestParam("roleId") Long roleId,
@RequestParam("scopeType") String scopeType,
@RequestParam("objectType") String objectType);
@GetMapping(PREFIX + "/role-permission-detail")
@Operation(summary = "查询对象作用域角色菜单与权限聚合结果")
@Parameter(name = "roleId", description = "角色 ID", example = "1024", required = true)
@Parameter(name = "scopeType", description = "权限作用域类型", example = "object", required = true)
@Parameter(name = "objectType", description = "对象类型", example = "product", required = true)
CommonResult<ObjectRolePermissionRespDTO> getObjectRolePermissionDetail(@RequestParam("roleId") Long roleId,
@RequestParam("scopeType") String scopeType,
@RequestParam("objectType") String objectType);
/**
* 按角色 ID 返回对象作用域角色摘要映射,便于业务模块批量对齐本地成员数据。
*
* @param roleIds 角色 ID 集合
* @param scopeType 权限作用域类型
* @param objectType 对象类型
* @return 角色摘要映射
*/
default Map<Long, ObjectRoleRespDTO> getObjectRoleMap(Collection<Long> roleIds, String scopeType, String objectType) {
if (CollUtil.isEmpty(roleIds)) {
return MapUtil.empty();
}
List<ObjectRoleRespDTO> roles = getObjectRoleList(roleIds, scopeType, objectType).getCheckedData();
return CollectionUtils.convertMap(roles, ObjectRoleRespDTO::getId);
}
}

View File

@@ -0,0 +1,34 @@
package com.njcn.rdms.module.system.api.permission.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "RPC 服务 - 对象作用域菜单 Response DTO")
@Data
public class ObjectMenuRespDTO {
@Schema(description = "菜单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2001")
private Long id;
@Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "产品设置")
private String name;
@Schema(description = "权限标识", example = "project:product:update")
private String permission;
@Schema(description = "菜单类型;允许返回目录、菜单、按钮,业务侧可按 type 再拆分导航或按钮", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
private Integer type;
@Schema(description = "显示排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
private Integer sort;
@Schema(description = "路由路径", example = "/project/product/detail")
private String path;
@Schema(description = "菜单图标", example = "ep:box")
private String icon;
@Schema(description = "是否可见", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
private Boolean visible;
}

View File

@@ -0,0 +1,23 @@
package com.njcn.rdms.module.system.api.permission.dto;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
import java.util.Set;
@Schema(description = "RPC 服务 - 对象作用域角色权限聚合 Response DTO")
@Data
public class ObjectRolePermissionRespDTO {
@Schema(description = "当前查询 roleId 对应的角色摘要,不表示登录态上下文里的当前用户角色")
private ObjectRoleRespDTO currentRole;
@ArraySchema(schema = @Schema(description = "当前查询角色在指定 scopeType/objectType 下可消费的已启用菜单资源明细;允许包含目录、菜单、按钮,业务侧可按 type 再拆分导航或按钮"))
private List<ObjectMenuRespDTO> menus;
@ArraySchema(schema = @Schema(description = "基于同一批有效菜单资源归一化提取出的权限标识集合,供对象权限校验直接消费", example = "project:product:query"))
private Set<String> permissions;
}

View File

@@ -0,0 +1,25 @@
package com.njcn.rdms.module.system.api.permission.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "RPC 服务 - 对象作用域角色摘要 Response DTO")
@Data
public class ObjectRoleRespDTO {
@Schema(description = "角色 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long id;
@Schema(description = "角色编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "product_manager")
private String code;
@Schema(description = "角色名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "产品经理")
private String name;
@Schema(description = "权限作用域类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "object")
private String scopeType;
@Schema(description = "对象类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "product")
private String objectType;
}