mirror of
				https://github.com/continew-org/continew-admin.git
				synced 2025-10-31 22:57:17 +08:00 
			
		
		
		
	fix: 存储管理及菜单管理功能优化 (#52)
存储管理功能优化: 1、私钥脱敏修改为注解/数据库敏感字段加密 2、兼容私钥脱敏修改场景下的数据回带 3、修复存储配置禁用情况下修改报错 || -> && 菜单管理优化: 1、非外链类型菜单兼容"/"路径
This commit is contained in:
		| @@ -21,6 +21,7 @@ import lombok.Data; | ||||
| import top.continew.admin.common.enums.DisEnableStatusEnum; | ||||
| import top.continew.admin.system.enums.StorageTypeEnum; | ||||
| import top.continew.starter.extension.crud.model.entity.BaseDO; | ||||
| import top.continew.starter.security.crypto.annotation.FieldEncrypt; | ||||
|  | ||||
| import java.io.Serial; | ||||
|  | ||||
| @@ -55,11 +56,13 @@ public class StorageDO extends BaseDO { | ||||
|     /** | ||||
|      * Access Key(访问密钥) | ||||
|      */ | ||||
|     @FieldEncrypt | ||||
|     private String accessKey; | ||||
|  | ||||
|     /** | ||||
|      * Secret Key(私有密钥) | ||||
|      */ | ||||
|     @FieldEncrypt | ||||
|     private String secretKey; | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -21,6 +21,7 @@ import lombok.Data; | ||||
| import top.continew.admin.common.enums.DisEnableStatusEnum; | ||||
| import top.continew.admin.system.enums.StorageTypeEnum; | ||||
| import top.continew.starter.extension.crud.model.resp.BaseDetailResp; | ||||
| import top.continew.starter.security.mask.annotation.JsonMask; | ||||
|  | ||||
| import java.io.Serial; | ||||
|  | ||||
| @@ -71,14 +72,9 @@ public class StorageResp extends BaseDetailResp { | ||||
|      * 私有密钥 | ||||
|      */ | ||||
|     @Schema(description = "私有密钥", example = "") | ||||
|     @JsonMask(left = 4, right = 3) | ||||
|     private String secretKey; | ||||
|  | ||||
|     /** | ||||
|      * 私有密钥加密串 | ||||
|      */ | ||||
|     @Schema(description = "私有密钥加密串", example = "") | ||||
|     private String secretKeyEncrypted; | ||||
|  | ||||
|     /** | ||||
|      * 终端节点 | ||||
|      */ | ||||
| @@ -119,4 +115,5 @@ public class StorageResp extends BaseDetailResp { | ||||
|     public Boolean getDisabled() { | ||||
|         return this.getIsDefault(); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -22,6 +22,7 @@ import cn.hutool.core.util.StrUtil; | ||||
| import cn.hutool.core.util.URLUtil; | ||||
| import jakarta.annotation.Resource; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import org.dromara.x.file.storage.core.FileStorageProperties; | ||||
| import org.dromara.x.file.storage.core.FileStorageService; | ||||
| import org.dromara.x.file.storage.core.FileStorageServiceBuilder; | ||||
| @@ -57,51 +58,33 @@ import java.util.concurrent.CopyOnWriteArrayList; | ||||
|  */ | ||||
| @Service | ||||
| @RequiredArgsConstructor | ||||
| @Slf4j | ||||
| public class StorageServiceImpl extends BaseServiceImpl<StorageMapper, StorageDO, StorageResp, StorageResp, StorageQuery, StorageReq> implements StorageService { | ||||
|  | ||||
|     private final FileStorageService fileStorageService; | ||||
|     @Resource | ||||
|     private FileService fileService; | ||||
|  | ||||
|     @Override | ||||
|     protected void fill(Object obj) { | ||||
|         super.fill(obj); | ||||
|         if (obj instanceof StorageResp resp && StrUtil.isNotBlank(resp.getSecretKey())) { | ||||
|             resp.setSecretKeyEncrypted(SecureUtils.encryptByRsaPublicKey(resp.getSecretKey())); | ||||
|             resp.setSecretKey(StrUtil.hide(resp.getSecretKey(), 4, resp.getSecretKey().length() - 3)); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void beforeAdd(StorageReq req) { | ||||
|         decryptSecretKey(req); | ||||
|         decodeSecretKey(req, null); | ||||
|         CheckUtils.throwIf(Boolean.TRUE.equals(req.getIsDefault()) && this.isDefaultExists(null), "请先取消原有默认存储"); | ||||
|         String code = req.getCode(); | ||||
|         CheckUtils.throwIf(this.isCodeExists(code, null), "新增失败,[{}] 已存在", code); | ||||
|         this.load(req); | ||||
|     } | ||||
|  | ||||
|     private void decryptSecretKey(StorageReq req) { | ||||
|         if (!StorageTypeEnum.S3.equals(req.getType())) { | ||||
|             return; | ||||
|         } | ||||
|         String secretKey = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(req.getSecretKey())); | ||||
|         ValidationUtils.throwIfNull(secretKey, "密钥解密失败"); | ||||
|         req.setSecretKey(secretKey); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void beforeUpdate(StorageReq req, Long id) { | ||||
|         decryptSecretKey(req); | ||||
|         String code = req.getCode(); | ||||
|         CheckUtils.throwIf(this.isCodeExists(code, id), "修改失败,[{}] 已存在", code); | ||||
|         DisEnableStatusEnum newStatus = req.getStatus(); | ||||
|         StorageDO oldStorage = super.getById(id); | ||||
|         CheckUtils.throwIf(Boolean.TRUE.equals(oldStorage.getIsDefault()) && DisEnableStatusEnum.DISABLE | ||||
|             .equals(newStatus), "[{}] 是默认存储,不允许禁用", oldStorage.getName()); | ||||
|         decodeSecretKey(req, oldStorage); | ||||
|         DisEnableStatusEnum oldStatus = oldStorage.getStatus(); | ||||
|         if (DisEnableStatusEnum.ENABLE.equals(oldStatus) || DisEnableStatusEnum.DISABLE.equals(newStatus)) { | ||||
|         if (DisEnableStatusEnum.ENABLE.equals(oldStatus) && DisEnableStatusEnum.DISABLE.equals(newStatus)) { | ||||
|             this.unload(BeanUtil.copyProperties(oldStorage, StorageReq.class)); | ||||
|         } | ||||
|         if (DisEnableStatusEnum.ENABLE.equals(newStatus)) { | ||||
| @@ -113,6 +96,23 @@ public class StorageServiceImpl extends BaseServiceImpl<StorageMapper, StorageDO | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private void decodeSecretKey(StorageReq req, StorageDO storage) { | ||||
|         if (!StorageTypeEnum.S3.equals(req.getType())) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         // 修改Storage时,如果SecretKey不修改,字段脱敏无法回带手动设置 | ||||
|         if ((StrUtil.isBlank(req.getSecretKey()) || req.getSecretKey().contains("*")) && StrUtil.isNotBlank(storage | ||||
|             .getSecretKey())) { | ||||
|             req.setSecretKey(storage.getSecretKey()); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         String secretKey = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(req.getSecretKey())); | ||||
|         ValidationUtils.throwIfNull(secretKey, "私有密钥解密失败"); | ||||
|         req.setSecretKey(secretKey); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void beforeDelete(List<Long> ids) { | ||||
|         CheckUtils.throwIf(fileService.countByStorageIds(ids) > 0, "所选存储存在文件关联,请删除文件后重试"); | ||||
|   | ||||
| @@ -18,6 +18,7 @@ package top.continew.admin.webapi.system; | ||||
|  | ||||
| import cn.dev33.satoken.annotation.SaCheckPermission; | ||||
| import cn.hutool.core.util.ObjectUtil; | ||||
| import cn.hutool.core.util.StrUtil; | ||||
| import io.swagger.v3.oas.annotations.tags.Tag; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
| import org.springframework.web.bind.annotation.PathVariable; | ||||
| @@ -27,6 +28,7 @@ import top.continew.admin.system.model.query.MenuQuery; | ||||
| import top.continew.admin.system.model.req.MenuReq; | ||||
| import top.continew.admin.system.model.resp.MenuResp; | ||||
| import top.continew.admin.system.service.MenuService; | ||||
| import top.continew.starter.core.constant.StringConstants; | ||||
| import top.continew.starter.core.util.URLUtils; | ||||
| import top.continew.starter.core.util.validate.ValidationUtils; | ||||
| import top.continew.starter.extension.crud.annotation.CrudRequestMapping; | ||||
| @@ -69,6 +71,11 @@ public class MenuController extends BaseController<MenuService, MenuResp, MenuRe | ||||
|         Boolean isExternal = ObjectUtil.defaultIfNull(req.getIsExternal(), false); | ||||
|         String path = req.getPath(); | ||||
|         ValidationUtils.throwIf(isExternal && !URLUtils.isHttpUrl(path), "路由地址格式错误,请以 http:// 或 https:// 开头"); | ||||
|         ValidationUtils.throwIf(!isExternal && URLUtils.isHttpUrl(path), "路由地址格式错误"); | ||||
|         if (!isExternal) { | ||||
|             ValidationUtils.throwIf(URLUtils.isHttpUrl(path), "路由地址格式错误"); | ||||
|             req.setPath(StrUtil.prependIfMissing(req.getPath(), StringConstants.SLASH)); | ||||
|             req.setName(StrUtil.removePrefix(req.getName(), StringConstants.SLASH)); | ||||
|             req.setComponent(StrUtil.removePrefix(req.getComponent(), StringConstants.SLASH)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 kils
					kils