diff --git a/backend/services/project-management/src/main/java/io/metersphere/project/controller/FileManagementController.java b/backend/services/project-management/src/main/java/io/metersphere/project/controller/FileManagementController.java index 07dfff0863..54524f1bbb 100644 --- a/backend/services/project-management/src/main/java/io/metersphere/project/controller/FileManagementController.java +++ b/backend/services/project-management/src/main/java/io/metersphere/project/controller/FileManagementController.java @@ -7,6 +7,7 @@ import io.metersphere.project.service.FileManagementService; import io.metersphere.project.service.FileMetadataService; import io.metersphere.sdk.constants.PermissionConstants; import io.metersphere.sdk.constants.StorageType; +import io.metersphere.system.security.CheckOwner; import io.metersphere.system.utils.Pager; import io.metersphere.system.utils.SessionUtils; import io.swagger.v3.oas.annotations.Operation; @@ -64,19 +65,20 @@ public class FileManagementController { @Operation(summary = "项目管理-文件管理-上传文件") @RequiresPermissions(PermissionConstants.PROJECT_FILE_MANAGEMENT_READ_ADD) public String upload(@Validated @RequestPart("request") FileUploadRequest request, @RequestPart(value = "file", required = false) MultipartFile uploadFile) throws Exception { - return fileMetadataService.upload(request, SessionUtils.getUserId(), uploadFile); + return fileMetadataService.upload(request, SessionUtils.getUserId(), uploadFile); } @PostMapping("/re-upload") @Operation(summary = "项目管理-文件管理-重新上传文件") @RequiresPermissions(PermissionConstants.PROJECT_FILE_MANAGEMENT_READ_UPDATE) public String reUpload(@Validated @RequestPart("request") FileReUploadRequest request, @RequestPart(value = "file", required = false) MultipartFile uploadFile) throws Exception { - return fileMetadataService.reUpload(request, SessionUtils.getUserId(), uploadFile); + return fileMetadataService.reUpload(request, SessionUtils.getUserId(), uploadFile); } @GetMapping(value = "/download/{id}") @Operation(summary = "项目管理-文件管理-下载文件") @RequiresPermissions(PermissionConstants.PROJECT_FILE_MANAGEMENT_READ_DOWNLOAD) + @CheckOwner(resourceId = "#id", resourceType = "file_metadata") public ResponseEntity download(@PathVariable String id) throws Exception { return fileMetadataService.downloadById(id); } diff --git a/backend/services/system-setting/src/main/java/io/metersphere/system/mapper/ExtCheckOwnerMapper.java b/backend/services/system-setting/src/main/java/io/metersphere/system/mapper/ExtCheckOwnerMapper.java new file mode 100644 index 0000000000..37a827288d --- /dev/null +++ b/backend/services/system-setting/src/main/java/io/metersphere/system/mapper/ExtCheckOwnerMapper.java @@ -0,0 +1,7 @@ +package io.metersphere.system.mapper; + +import org.apache.ibatis.annotations.Param; + +public interface ExtCheckOwnerMapper { + boolean checkoutOwner(@Param("table") String resourceType, @Param("projectId") String projectId, @Param("id") String id); +} diff --git a/backend/services/system-setting/src/main/java/io/metersphere/system/mapper/ExtCheckOwnerMapper.xml b/backend/services/system-setting/src/main/java/io/metersphere/system/mapper/ExtCheckOwnerMapper.xml new file mode 100644 index 0000000000..87a60db473 --- /dev/null +++ b/backend/services/system-setting/src/main/java/io/metersphere/system/mapper/ExtCheckOwnerMapper.xml @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file diff --git a/backend/services/system-setting/src/main/java/io/metersphere/system/security/CheckOwner.java b/backend/services/system-setting/src/main/java/io/metersphere/system/security/CheckOwner.java new file mode 100644 index 0000000000..442098c616 --- /dev/null +++ b/backend/services/system-setting/src/main/java/io/metersphere/system/security/CheckOwner.java @@ -0,0 +1,12 @@ +package io.metersphere.system.security; + +import java.lang.annotation.*; + +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface CheckOwner { + String resourceId(); + + String resourceType(); +} diff --git a/backend/services/system-setting/src/main/java/io/metersphere/system/security/CheckOwnerAspect.java b/backend/services/system-setting/src/main/java/io/metersphere/system/security/CheckOwnerAspect.java new file mode 100644 index 0000000000..cd13cb3aca --- /dev/null +++ b/backend/services/system-setting/src/main/java/io/metersphere/system/security/CheckOwnerAspect.java @@ -0,0 +1,82 @@ +package io.metersphere.system.security; + + +import io.metersphere.sdk.constants.InternalUserRole; +import io.metersphere.sdk.exception.MSException; +import io.metersphere.sdk.util.LogUtils; +import io.metersphere.sdk.util.Translator; +import io.metersphere.system.mapper.ExtCheckOwnerMapper; +import io.metersphere.system.utils.SessionUtils; +import jakarta.annotation.Resource; +import org.apache.commons.lang3.StringUtils; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.core.StandardReflectionParameterNameDiscoverer; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Method; + + +@Aspect +@Component +public class CheckOwnerAspect { + + private ExpressionParser parser = new SpelExpressionParser(); + private StandardReflectionParameterNameDiscoverer discoverer = new StandardReflectionParameterNameDiscoverer(); + + @Resource + private ExtCheckOwnerMapper extCheckOwnerMapper; + + @Pointcut("@annotation(io.metersphere.system.security.CheckOwner)") + public void pointcut() { + } + + @Before("pointcut()") + public void before(JoinPoint joinPoint) { + try { + //从切面织入点处通过反射机制获取织入点处的方法 + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + //获取切入点所在的方法 + Method method = signature.getMethod(); + //获取参数对象数组 + Object[] args = joinPoint.getArgs(); + CheckOwner checkOwner = method.getAnnotation(CheckOwner.class); + long count = SessionUtils.getUser().getUserRoles() + .stream() + .filter(g -> StringUtils.equalsIgnoreCase(g.getId(), InternalUserRole.ADMIN.getValue())) + .count(); + if (count > 0) { + return; + } + // 操作内容 + //获取方法参数名 + String[] params = discoverer.getParameterNames(method); + //将参数纳入Spring管理 + EvaluationContext context = new StandardEvaluationContext(); + for (int len = 0; len < params.length; len++) { + context.setVariable(params[len], args[len]); + } + + String resourceId = checkOwner.resourceId(); + String resourceType = checkOwner.resourceType(); + Expression titleExp = parser.parseExpression(resourceId); + Object v = titleExp.getValue(context, Object.class); + if (v instanceof String id) { + if (!extCheckOwnerMapper.checkoutOwner(resourceType, SessionUtils.getCurrentProjectId(), id)) { + throw new MSException(Translator.get("check_owner_case")); + } + } + } catch (Exception e) { + LogUtils.error(e.getMessage(), e); + } + } + +}