微调
This commit is contained in:
@@ -26,6 +26,7 @@ public interface ErrorCodeConstants {
|
||||
ErrorCode MENU_EXISTS_CHILDREN = new ErrorCode(1_002_001_004, "存在子菜单,无法删除");
|
||||
ErrorCode MENU_PARENT_NOT_DIR_OR_MENU = new ErrorCode(1_002_001_005, "父菜单的类型必须是目录或者菜单");
|
||||
ErrorCode MENU_COMPONENT_NAME_DUPLICATE = new ErrorCode(1_002_001_006, "已经存在该组件名的菜单");
|
||||
ErrorCode MENU_NOT_ENABLE = new ErrorCode(1_002_001_007, "名字为【{}】的菜单已被禁用");
|
||||
|
||||
// ========== 角色模块 1-002-002-000 ==========
|
||||
ErrorCode ROLE_NOT_EXISTS = new ErrorCode(1_002_002_000, "角色不存在");
|
||||
|
||||
@@ -55,6 +55,9 @@ public class OAuth2UserController {
|
||||
public CommonResult<OAuth2UserInfoRespVO> getUserInfo() {
|
||||
// 获得用户基本信息
|
||||
AdminUserDO user = userService.getUser(getLoginUserId());
|
||||
if (user == null) {
|
||||
return success(null);
|
||||
}
|
||||
OAuth2UserInfoRespVO resp = BeanUtils.toBean(user, OAuth2UserInfoRespVO.class);
|
||||
// 获得部门信息
|
||||
if (user.getDeptId() != null) {
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package com.njcn.rdms.module.system.controller.admin.permission;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.njcn.rdms.framework.common.pojo.CommonResult;
|
||||
import com.njcn.rdms.module.system.controller.admin.permission.vo.permission.PermissionAssignRoleDataScopeReqVO;
|
||||
import com.njcn.rdms.module.system.controller.admin.permission.vo.permission.PermissionAssignRoleMenuReqVO;
|
||||
import com.njcn.rdms.module.system.controller.admin.permission.vo.permission.PermissionAssignUserRoleReqVO;
|
||||
import com.njcn.rdms.module.system.service.permission.PermissionService;
|
||||
@@ -15,7 +13,6 @@ import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
|
||||
@@ -51,14 +48,6 @@ public class PermissionController {
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PostMapping("/assign-role-data-scope")
|
||||
@Operation(summary = "赋予角色数据权限")
|
||||
@PreAuthorize("@ss.hasPermission('system:permission:assign-role-data-scope')")
|
||||
public CommonResult<Boolean> assignRoleDataScope(@Valid @RequestBody PermissionAssignRoleDataScopeReqVO reqVO) {
|
||||
permissionService.assignRoleDataScope(reqVO.getRoleId(), reqVO.getDataScope(), reqVO.getDataScopeDeptIds());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Operation(summary = "获得管理员拥有的角色编号列表")
|
||||
@Parameter(name = "userId", description = "用户编号", required = true)
|
||||
@GetMapping("/list-user-roles")
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.njcn.rdms.module.system.controller.admin.permission.vo.permission;
|
||||
|
||||
import com.njcn.rdms.framework.common.validation.InEnum;
|
||||
import com.njcn.rdms.module.system.enums.permission.DataScopeEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
@Schema(description = "管理后台 - 赋予角色数据权限 Request VO")
|
||||
@Data
|
||||
public class PermissionAssignRoleDataScopeReqVO {
|
||||
|
||||
@Schema(description = "角色编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "角色编号不能为空")
|
||||
private Long roleId;
|
||||
|
||||
@Schema(description = "数据范围,参见 DataScopeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "数据范围不能为空")
|
||||
@InEnum(value = DataScopeEnum.class, message = "数据范围必须是 {value}")
|
||||
private Integer dataScope;
|
||||
|
||||
@Schema(description = "部门编号列表,只有范围类型为 DEPT_CUSTOM 时,该字段才需要", example = "1,3,5")
|
||||
private Set<Long> dataScopeDeptIds = Collections.emptySet(); // 兜底
|
||||
|
||||
}
|
||||
@@ -10,7 +10,6 @@ import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Set;
|
||||
|
||||
@Schema(description = "管理后台 - 角色信息 Response VO")
|
||||
@Data
|
||||
@@ -45,14 +44,6 @@ public class RoleRespVO {
|
||||
@Schema(description = "备注", example = "我是一个角色")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "数据范围,参见 DataScopeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@ExcelProperty(value = "数据范围", converter = DictConvert.class)
|
||||
@DictFormat(DictTypeConstants.DATA_SCOPE)
|
||||
private Integer dataScope;
|
||||
|
||||
@Schema(description = "数据范围(指定部门数组)", example = "1")
|
||||
private Set<Long> dataScopeDeptIds;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.njcn.rdms.module.system.controller.admin.user;
|
||||
|
||||
import com.njcn.rdms.framework.common.pojo.CommonResult;
|
||||
import com.njcn.rdms.framework.common.enums.CommonStatusEnum;
|
||||
import com.njcn.rdms.module.system.controller.admin.user.vo.profile.UserProfileRespVO;
|
||||
import com.njcn.rdms.module.system.controller.admin.user.vo.profile.UserProfileUpdatePasswordReqVO;
|
||||
import com.njcn.rdms.module.system.controller.admin.user.vo.profile.UserProfileUpdateReqVO;
|
||||
@@ -54,8 +55,12 @@ public class UserProfileController {
|
||||
public CommonResult<UserProfileRespVO> getUserProfile() {
|
||||
// 获得用户基本信息
|
||||
AdminUserDO user = userService.getUser(getLoginUserId());
|
||||
if (user == null) {
|
||||
return success(null);
|
||||
}
|
||||
// 获得用户角色
|
||||
List<RoleDO> userRoles = roleService.getRoleListFromCache(permissionService.getUserRoleIdListByUserId(user.getId()));
|
||||
userRoles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus()));
|
||||
// 获得部门信息
|
||||
DeptDO dept = user.getDeptId() != null ? deptService.getDept(user.getDeptId()) : null;
|
||||
// 获得主岗位信息
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.njcn.rdms.module.system.convert.auth;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.njcn.rdms.framework.common.util.object.BeanUtils;
|
||||
import com.njcn.rdms.module.system.controller.admin.auth.vo.AuthPermissionInfoRespVO;
|
||||
import com.njcn.rdms.module.system.dal.dataobject.permission.MenuDO;
|
||||
@@ -32,7 +33,8 @@ public interface AuthConvert {
|
||||
return AuthPermissionInfoRespVO.builder()
|
||||
.user(BeanUtils.toBean(user, AuthPermissionInfoRespVO.UserVO.class))
|
||||
.roles(convertSet(roleList, RoleDO::getCode))
|
||||
.permissions(convertSet(menuList, MenuDO::getPermission))
|
||||
.permissions(convertSet(filterList(menuList, menu -> StrUtil.isNotBlank(menu.getPermission())),
|
||||
MenuDO::getPermission))
|
||||
.menus(buildMenuTree(menuList))
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -29,4 +29,13 @@ public interface MenuService {
|
||||
|
||||
List<MenuDO> getMenuList(Collection<Long> ids);
|
||||
|
||||
/**
|
||||
* 校验菜单们是否有效。如下情况,视为无效:
|
||||
* 1. 菜单编号不存在
|
||||
* 2. 菜单被禁用
|
||||
*
|
||||
* @param ids 菜单编号数组
|
||||
*/
|
||||
void validateMenuList(Collection<Long> ids);
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@@ -109,6 +108,9 @@ public class MenuServiceImpl implements MenuService {
|
||||
public void deleteMenuList(List<Long> ids) {
|
||||
// 校验是否还有子菜单
|
||||
ids.forEach(id -> {
|
||||
if (menuMapper.selectById(id) == null) {
|
||||
throw exception(MENU_NOT_EXISTS);
|
||||
}
|
||||
if (menuMapper.selectCountByParentId(id) > 0) {
|
||||
throw exception(MENU_EXISTS_CHILDREN);
|
||||
}
|
||||
@@ -197,6 +199,24 @@ public class MenuServiceImpl implements MenuService {
|
||||
return menuMapper.selectByIds(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateMenuList(Collection<Long> ids) {
|
||||
if (CollUtil.isEmpty(ids)) {
|
||||
return;
|
||||
}
|
||||
List<MenuDO> menus = menuMapper.selectByIds(ids);
|
||||
Map<Long, MenuDO> menuMap = convertMap(menus, MenuDO::getId);
|
||||
ids.forEach(id -> {
|
||||
MenuDO menu = menuMap.get(id);
|
||||
if (menu == null) {
|
||||
throw exception(MENU_NOT_EXISTS);
|
||||
}
|
||||
if (CommonStatusEnum.isDisable(menu.getStatus())) {
|
||||
throw exception(MENU_NOT_ENABLE, menu.getName());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验父菜单是否合法
|
||||
* <p>
|
||||
|
||||
@@ -8,7 +8,7 @@ import static java.util.Collections.singleton;
|
||||
/**
|
||||
* 权限 Service 接口
|
||||
* <p>
|
||||
* 提供用户-角色、角色-菜单、角色-部门的关联权限处理
|
||||
* 提供用户-角色、角色-菜单的关联权限处理
|
||||
*
|
||||
* @author hongawen
|
||||
*/
|
||||
@@ -122,16 +122,4 @@ public interface PermissionService {
|
||||
*/
|
||||
Set<Long> getUserRoleIdListByUserIdFromCache(Long userId);
|
||||
|
||||
// ========== 用户-部门的相关方法 ==========
|
||||
|
||||
/**
|
||||
* 设置角色的数据权限
|
||||
*
|
||||
* @param roleId 角色编号
|
||||
* @param dataScope 数据范围
|
||||
* @param dataScopeDeptIds 部门编号数组
|
||||
*/
|
||||
void assignRoleDataScope(Long roleId, Integer dataScope, Set<Long> dataScopeDeptIds);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ import com.njcn.rdms.module.system.dal.dataobject.permission.UserRoleDO;
|
||||
import com.njcn.rdms.module.system.dal.mysql.permission.RoleMenuMapper;
|
||||
import com.njcn.rdms.module.system.dal.mysql.permission.UserRoleMapper;
|
||||
import com.njcn.rdms.module.system.dal.redis.RedisKeyConstants;
|
||||
import com.njcn.rdms.module.system.service.dept.DeptService;
|
||||
import com.njcn.rdms.module.system.service.user.AdminUserService;
|
||||
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
@@ -49,8 +48,6 @@ public class PermissionServiceImpl implements PermissionService {
|
||||
@Resource
|
||||
private MenuService menuService;
|
||||
@Resource
|
||||
private DeptService deptService;
|
||||
@Resource
|
||||
private AdminUserService userService;
|
||||
|
||||
@Override
|
||||
@@ -90,10 +87,14 @@ public class PermissionServiceImpl implements PermissionService {
|
||||
if (CollUtil.isEmpty(menuIds)) {
|
||||
return false;
|
||||
}
|
||||
List<MenuDO> menus = getEnablePermissionMenus(menuIds);
|
||||
if (CollUtil.isEmpty(menus)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 判断是否有权限
|
||||
Set<Long> roleIds = convertSet(roles, RoleDO::getId);
|
||||
for (Long menuId : menuIds) {
|
||||
for (Long menuId : convertSet(menus, MenuDO::getId)) {
|
||||
// 获得拥有该菜单的角色编号集合
|
||||
Set<Long> menuRoleIds = getSelf().getMenuRoleIdListByMenuIdFromCache(menuId);
|
||||
// 如果有交集,说明有权限
|
||||
@@ -104,6 +105,29 @@ public class PermissionServiceImpl implements PermissionService {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载权限菜单自身及其父链后,再统一过滤禁用节点,避免仅查询按钮节点时误判父菜单缺失。
|
||||
*/
|
||||
private List<MenuDO> getEnablePermissionMenus(Collection<Long> menuIds) {
|
||||
Set<Long> targetMenuIds = new HashSet<>(menuIds);
|
||||
Map<Long, MenuDO> menuMap = new LinkedHashMap<>();
|
||||
Set<Long> currentIds = new HashSet<>(menuIds);
|
||||
while (CollUtil.isNotEmpty(currentIds)) {
|
||||
List<MenuDO> currentMenus = menuService.getMenuList(currentIds);
|
||||
if (CollUtil.isEmpty(currentMenus)) {
|
||||
break;
|
||||
}
|
||||
currentMenus.forEach(menu -> menuMap.put(menu.getId(), menu));
|
||||
Set<Long> parentIds = convertSet(currentMenus, MenuDO::getParentId);
|
||||
parentIds.remove(MenuDO.ID_ROOT);
|
||||
parentIds.removeIf(menuMap::containsKey);
|
||||
currentIds = parentIds;
|
||||
}
|
||||
List<MenuDO> enabledMenus = menuService.filterDisableMenus(new ArrayList<>(menuMap.values()));
|
||||
enabledMenus.removeIf(menu -> !targetMenuIds.contains(menu.getId()));
|
||||
return enabledMenus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAnyRoles(Long userId, String... roles) {
|
||||
// 如果为空,说明已经有权限
|
||||
@@ -133,6 +157,8 @@ public class PermissionServiceImpl implements PermissionService {
|
||||
allEntries = true) // allEntries 清空所有缓存,主要一次更新涉及到的 menuIds 较多,反倒批量会更快
|
||||
})
|
||||
public void assignRoleMenu(Long roleId, Set<Long> menuIds) {
|
||||
roleService.validateRoleList(Collections.singleton(roleId));
|
||||
menuService.validateMenuList(menuIds);
|
||||
// 获得角色拥有菜单编号
|
||||
Set<Long> dbMenuIds = convertSet(roleMenuMapper.selectListByRoleId(roleId), RoleMenuDO::getMenuId);
|
||||
// 计算新增和删除的菜单编号
|
||||
@@ -200,6 +226,8 @@ public class PermissionServiceImpl implements PermissionService {
|
||||
@DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换
|
||||
@CacheEvict(value = RedisKeyConstants.USER_ROLE_ID_LIST, key = "#userId")
|
||||
public void assignUserRole(Long userId, Set<Long> roleIds) {
|
||||
userService.validateUserList(Collections.singleton(userId));
|
||||
roleService.validateRoleList(roleIds);
|
||||
// 获得角色拥有角色编号
|
||||
Set<Long> dbRoleIds = convertSet(userRoleMapper.selectListByUserId(userId),
|
||||
UserRoleDO::getRoleId);
|
||||
@@ -259,14 +287,6 @@ public class PermissionServiceImpl implements PermissionService {
|
||||
return roles;
|
||||
}
|
||||
|
||||
// ========== 用户-部门的相关方法 ==========
|
||||
|
||||
@Override
|
||||
public void assignRoleDataScope(Long roleId, Integer dataScope, Set<Long> dataScopeDeptIds) {
|
||||
roleService.updateRoleDataScope(roleId, dataScope, dataScopeDeptIds);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获得自身的代理对象,解决 AOP 生效问题
|
||||
*
|
||||
|
||||
@@ -8,7 +8,6 @@ import jakarta.validation.Valid;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 角色 Service 接口
|
||||
@@ -47,15 +46,6 @@ public interface RoleService {
|
||||
*/
|
||||
void deleteRoleList(List<Long> ids);
|
||||
|
||||
/**
|
||||
* 设置角色的数据权限
|
||||
*
|
||||
* @param id 角色编号
|
||||
* @param dataScope 数据范围
|
||||
* @param dataScopeDeptIds 部门编号数组
|
||||
*/
|
||||
void updateRoleDataScope(Long id, Integer dataScope, Set<Long> dataScopeDeptIds);
|
||||
|
||||
/**
|
||||
* 获得角色
|
||||
*
|
||||
|
||||
@@ -14,7 +14,6 @@ import com.njcn.rdms.module.system.controller.admin.permission.vo.role.RoleSaveR
|
||||
import com.njcn.rdms.module.system.dal.dataobject.permission.RoleDO;
|
||||
import com.njcn.rdms.module.system.dal.mysql.permission.RoleMapper;
|
||||
import com.njcn.rdms.module.system.dal.redis.RedisKeyConstants;
|
||||
import com.njcn.rdms.module.system.enums.permission.DataScopeEnum;
|
||||
import com.njcn.rdms.module.system.enums.permission.RoleCodeEnum;
|
||||
import com.njcn.rdms.module.system.enums.permission.RoleTypeEnum;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
@@ -29,7 +28,10 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.njcn.rdms.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static com.njcn.rdms.framework.common.util.collection.CollectionUtils.convertMap;
|
||||
@@ -62,8 +64,7 @@ public class RoleServiceImpl implements RoleService {
|
||||
// 2. 插入到数据库
|
||||
RoleDO role = BeanUtils.toBean(createReqVO, RoleDO.class)
|
||||
.setType(ObjectUtil.defaultIfNull(type, RoleTypeEnum.CUSTOM.getType()))
|
||||
.setStatus(ObjUtil.defaultIfNull(createReqVO.getStatus(), CommonStatusEnum.ENABLE.getStatus()))
|
||||
.setDataScope(DataScopeEnum.ALL.getScope()); // 默认可查看所有数据。原因是,可能一些项目不需要项目权限
|
||||
.setStatus(ObjUtil.defaultIfNull(createReqVO.getStatus(), CommonStatusEnum.ENABLE.getStatus()));
|
||||
roleMapper.insert(role);
|
||||
|
||||
// 3. 记录操作日志上下文
|
||||
@@ -90,20 +91,6 @@ public class RoleServiceImpl implements RoleService {
|
||||
LogRecordContext.putVariable("role", role);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheEvict(value = RedisKeyConstants.ROLE, key = "#id")
|
||||
public void updateRoleDataScope(Long id, Integer dataScope, Set<Long> dataScopeDeptIds) {
|
||||
// 校验是否可以更新
|
||||
validateRoleForUpdate(id);
|
||||
|
||||
// 更新数据范围
|
||||
RoleDO updateObject = new RoleDO();
|
||||
updateObject.setId(id);
|
||||
updateObject.setDataScope(dataScope);
|
||||
updateObject.setDataScopeDeptIds(dataScopeDeptIds);
|
||||
roleMapper.updateById(updateObject);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@CacheEvict(value = RedisKeyConstants.ROLE, key = "#id")
|
||||
@@ -124,6 +111,7 @@ public class RoleServiceImpl implements RoleService {
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@CacheEvict(value = RedisKeyConstants.ROLE, allEntries = true)
|
||||
public void deleteRoleList(List<Long> ids) {
|
||||
// 1. 校验是否可以删除
|
||||
ids.forEach(this::validateRoleForUpdate);
|
||||
|
||||
@@ -220,6 +220,7 @@ public class AdminUserServiceImpl implements AdminUserService {
|
||||
// 2. 删除用户及其关联数据
|
||||
userMapper.deleteById(id);
|
||||
permissionService.processUserDeleted(id);
|
||||
oauth2TokenService.removeAccessToken(id, UserTypeEnum.ADMIN.getValue());
|
||||
// 3. 记录操作日志上下文
|
||||
LogRecordContext.putVariable("user", user);
|
||||
}
|
||||
@@ -230,7 +231,10 @@ public class AdminUserServiceImpl implements AdminUserService {
|
||||
// 1. 批量删除用户
|
||||
userMapper.deleteByIds(ids);
|
||||
// 2. 批量删除用户关联数据
|
||||
ids.forEach(permissionService::processUserDeleted);
|
||||
ids.forEach(id -> {
|
||||
permissionService.processUserDeleted(id);
|
||||
oauth2TokenService.removeAccessToken(id, UserTypeEnum.ADMIN.getValue());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user