diff --git a/continew-system/src/main/java/top/continew/admin/system/service/UserRoleService.java b/continew-system/src/main/java/top/continew/admin/system/service/UserRoleService.java index f6289aa17..e756232e7 100644 --- a/continew-system/src/main/java/top/continew/admin/system/service/UserRoleService.java +++ b/continew-system/src/main/java/top/continew/admin/system/service/UserRoleService.java @@ -103,4 +103,18 @@ public interface UserRoleService { * @return 是否已关联(true:已关联;false:未关联) */ boolean isRoleIdExists(List roleIds); + + /** + * 检查系统内置用户是否在用户列表中,如果存在则抛出异常 + * + * @param userIds 用户 ID 列表 + */ + void checkSystemUserAssignment(List userIds); + + /** + * 检查系统内置用户是否在用户角色关联列表中,如果存在则抛出异常 + * + * @param userRoleIds 用户角色关联 ID 列表 + */ + void checkSystemUserUnassignment(List userRoleIds); } \ No newline at end of file diff --git a/continew-system/src/main/java/top/continew/admin/system/service/impl/FileServiceImpl.java b/continew-system/src/main/java/top/continew/admin/system/service/impl/FileServiceImpl.java index e1504007b..85da45a4e 100644 --- a/continew-system/src/main/java/top/continew/admin/system/service/impl/FileServiceImpl.java +++ b/continew-system/src/main/java/top/continew/admin/system/service/impl/FileServiceImpl.java @@ -235,7 +235,8 @@ private FileInfo upload(Object file, String parentPath, String storageCode, Stri // 生成唯一文件名(处理重名情况) String originalFileName = getOriginalFileName(file); - String uniqueFileName = FileNameGenerator.generateUniqueName(originalFileName, parentPath, storage.getId(), baseMapper); + String uniqueFileName = FileNameGenerator.generateUniqueName(originalFileName, parentPath, storage + .getId(), baseMapper); UploadPretreatment uploadPretreatment = fileStorageService.of(file) .setPlatform(storage.getCode()) diff --git a/continew-system/src/main/java/top/continew/admin/system/service/impl/MultipartUploadServiceImpl.java b/continew-system/src/main/java/top/continew/admin/system/service/impl/MultipartUploadServiceImpl.java index ef6bb67a3..995cc9218 100644 --- a/continew-system/src/main/java/top/continew/admin/system/service/impl/MultipartUploadServiceImpl.java +++ b/continew-system/src/main/java/top/continew/admin/system/service/impl/MultipartUploadServiceImpl.java @@ -104,7 +104,8 @@ public MultipartUploadInitResp initMultipartUpload(MultipartUploadInitReq multiP } // 生成唯一文件名(处理重名情况) - String uniqueFileName = FileNameGenerator.generateUniqueName(originalFileName, parentPath, storageDO.getId(), fileMapper); + String uniqueFileName = FileNameGenerator.generateUniqueName(originalFileName, parentPath, storageDO + .getId(), fileMapper); multiPartUploadInitReq.setFileName(uniqueFileName); StorageHandler storageHandler = storageHandlerFactory.createHandler(storageDO.getType()); diff --git a/continew-system/src/main/java/top/continew/admin/system/service/impl/RoleServiceImpl.java b/continew-system/src/main/java/top/continew/admin/system/service/impl/RoleServiceImpl.java index 7ff97946b..8cc84375a 100644 --- a/continew-system/src/main/java/top/continew/admin/system/service/impl/RoleServiceImpl.java +++ b/continew-system/src/main/java/top/continew/admin/system/service/impl/RoleServiceImpl.java @@ -164,6 +164,10 @@ public void updatePermission(Long id, RolePermissionUpdateReq req) { public void assignToUsers(Long id, List userIds) { RoleDO role = super.getById(id); CheckUtils.throwIf(Boolean.TRUE.equals(role.getIsSystem()), "[{}] 是系统内置角色,不允许分配角色给其他用户", role.getName()); + // 防止将系统内置用户分配给非超级管理员角色 + if (!SystemConstants.SUPER_ADMIN_ROLE_ID.equals(id)) { + userRoleService.checkSystemUserAssignment(userIds); + } // 保存用户和角色关联 userRoleService.assignRoleToUsers(id, userIds); // 更新用户上下文 diff --git a/continew-system/src/main/java/top/continew/admin/system/service/impl/UserRoleServiceImpl.java b/continew-system/src/main/java/top/continew/admin/system/service/impl/UserRoleServiceImpl.java index 172e5d5d0..2d2ab50ee 100644 --- a/continew-system/src/main/java/top/continew/admin/system/service/impl/UserRoleServiceImpl.java +++ b/continew-system/src/main/java/top/continew/admin/system/service/impl/UserRoleServiceImpl.java @@ -120,6 +120,8 @@ public boolean assignRoleToUsers(Long roleId, List userIds) { @Override public void deleteByIds(List ids) { + // 检查是否包含系统内置用户的角色关联 + this.checkSystemUserUnassignment(ids); baseMapper.deleteByIds(ids); } @@ -165,4 +167,42 @@ public boolean isRoleIdExists(List roleIds) { } return baseMapper.lambdaQuery().in(UserRoleDO::getRoleId, roleIds).exists(); } + + @Override + public void checkSystemUserAssignment(List userIds) { + if (CollUtil.isEmpty(userIds)) { + return; + } + // 查询用户列表中是否包含系统内置用户 + List systemUsers = userService.lambdaQuery() + .select(UserDO::getId, UserDO::getNickname) + .in(UserDO::getId, userIds) + .eq(UserDO::getIsSystem, true) + .list(); + CheckUtils.throwIfNotEmpty(systemUsers, "[{}] 是系统内置用户,不允许分配给非超级管理员角色", systemUsers.get(0).getNickname()); + } + + @Override + public void checkSystemUserUnassignment(List userRoleIds) { + if (CollUtil.isEmpty(userRoleIds)) { + return; + } + // 查询用户角色关联列表 + List userRoleList = baseMapper.lambdaQuery() + .select(UserRoleDO::getUserId) + .in(UserRoleDO::getId, userRoleIds) + .list(); + if (CollUtil.isEmpty(userRoleList)) { + return; + } + // 获取用户ID列表 + List userIds = userRoleList.stream().map(UserRoleDO::getUserId).distinct().toList(); + // 查询是否包含系统内置用户 + List systemUsers = userService.lambdaQuery() + .select(UserDO::getId, UserDO::getNickname) + .in(UserDO::getId, userIds) + .eq(UserDO::getIsSystem, true) + .list(); + CheckUtils.throwIfNotEmpty(systemUsers, "[{}] 是系统内置用户,不允许取消分配角色", systemUsers.get(0).getNickname()); + } } diff --git a/continew-system/src/main/java/top/continew/admin/system/util/FileNameGenerator.java b/continew-system/src/main/java/top/continew/admin/system/util/FileNameGenerator.java index 85a9004ce..29f6998ee 100644 --- a/continew-system/src/main/java/top/continew/admin/system/util/FileNameGenerator.java +++ b/continew-system/src/main/java/top/continew/admin/system/util/FileNameGenerator.java @@ -50,9 +50,9 @@ private FileNameGenerator() { *

* 当目标目录存在同名文件时,自动添加序号后缀: *

    - *
  • file.txt → file(1).txt → file(2).txt → ...
  • - *
  • 无扩展名:README → README(1) → README(2) → ...
  • - *
  • 隐藏文件:.gitignore → .gitignore(1) → .gitignore(2) → ...
  • + *
  • file.txt → file(1).txt → file(2).txt → ...
  • + *
  • 无扩展名:README → README(1) → README(2) → ...
  • + *
  • 隐藏文件:.gitignore → .gitignore(1) → .gitignore(2) → ...
  • *
*

* @@ -90,7 +90,9 @@ public static String generateUniqueName(String fileName, String parentPath, Long // 安全限制,防止无限循环 if (counter > 9999) { log.warn("文件名重命名超过最大限制,使用当前时间戳: {}", fileName); - return baseName + "_" + System.currentTimeMillis() + (StrUtil.isNotBlank(extension) ? "." + extension : ""); + return baseName + "_" + System.currentTimeMillis() + (StrUtil.isNotBlank(extension) + ? "." + extension + : ""); } } } @@ -102,10 +104,10 @@ public static String generateUniqueName(String fileName, String parentPath, Long * 示例: *

*
    - *
  • "document.pdf" → ["document", "pdf"]
  • - *
  • "README" → ["README", ""]
  • - *
  • ".gitignore" → [".gitignore", ""]
  • - *
  • "archive.tar.gz" → ["archive.tar", "gz"]
  • + *
  • "document.pdf" → ["document", "pdf"]
  • + *
  • "README" → ["README", ""]
  • + *
  • ".gitignore" → [".gitignore", ""]
  • + *
  • "archive.tar.gz" → ["archive.tar", "gz"]
  • *
* * @param fileName 文件名 @@ -113,7 +115,7 @@ public static String generateUniqueName(String fileName, String parentPath, Long */ public static String[] parseFileName(String fileName) { if (StrUtil.isBlank(fileName)) { - return new String[]{"", ""}; + return new String[] {"", ""}; } // 处理隐藏文件(以.开头) @@ -122,7 +124,7 @@ public static String[] parseFileName(String fileName) { // 处理空文件名(如只有"."的情况) if (nameWithoutDot.isEmpty()) { - return new String[]{fileName, ""}; + return new String[] {fileName, ""}; } // 查找最后一个点号位置 @@ -130,18 +132,20 @@ public static String[] parseFileName(String fileName) { // 点号不存在或在开头(如 ".bashrc"),视为无扩展名 if (lastDotIndex <= 0) { - return new String[]{fileName, ""}; + return new String[] {fileName, ""}; } - String baseName = isHidden ? "." + nameWithoutDot.substring(0, lastDotIndex) : nameWithoutDot.substring(0, lastDotIndex); + String baseName = isHidden + ? "." + nameWithoutDot.substring(0, lastDotIndex) + : nameWithoutDot.substring(0, lastDotIndex); String extension = nameWithoutDot.substring(lastDotIndex + 1); // 扩展名不应包含路径分隔符(安全检查) if (extension.contains("/") || extension.contains("\\")) { - return new String[]{fileName, ""}; + return new String[] {fileName, ""}; } - return new String[]{baseName, extension}; + return new String[] {baseName, extension}; } /** @@ -194,7 +198,10 @@ private static boolean existsByName(String parentPath, Long storageId, String na * @param fileMapper 文件Mapper * @return 文件名列表 */ - private static List selectNamesByParentPath(String parentPath, Long storageId, String namePrefix, FileMapper fileMapper) { + private static List selectNamesByParentPath(String parentPath, + Long storageId, + String namePrefix, + FileMapper fileMapper) { var wrapper = fileMapper.lambdaQuery() .eq(FileDO::getParentPath, parentPath) .eq(FileDO::getStorageId, storageId)