用户权限判断,默认继承目录权限

This commit is contained in:
2025-12-04 16:35:59 +08:00
parent 7e001fd13a
commit 1a59c1c1ec
5 changed files with 94 additions and 17 deletions

View File

@@ -123,6 +123,20 @@
<build>
<plugins>
<plugin>
<!-- 编译插件 parameters为了 切面PermissionCheckAspect能正确解析 #req.fileId、#fileId -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>17</source>
<target>17</target>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>

View File

@@ -6,7 +6,12 @@ import com.sdm.data.service.IFileUserPermissionService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.SimpleEvaluationContext;
import org.springframework.stereotype.Component;
import java.lang.annotation.ElementType;
@@ -18,27 +23,80 @@ import java.nio.file.AccessDeniedException;
@Aspect
@Component
public class PermissionCheckAspect {
@Autowired
private IFileUserPermissionService fileUserPermissionService;
private final ExpressionParser parser = new SpelExpressionParser();
private final EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
@Before("@annotation(filePermissionCheck)")
public void checkPermission(JoinPoint joinPoint, FilePermissionCheck filePermissionCheck) throws AccessDeniedException {
public void checkPermission(JoinPoint joinPoint, FilePermissionCheck filePermissionCheck){
Long userId = ThreadLocalContext.getUserId();
if (userId == null) {
throw new RuntimeException("用户未登录");
}
Object[] args = joinPoint.getArgs();
// 解析 fileId
Long fileId = resolveFileId(joinPoint, filePermissionCheck.fileIdExpression());
if (fileId == null) {
throw new RuntimeException("无法解析 fileId请检查 @FilePermissionCheck.fileIdExpression()");
}
Long fileId = 1L;
// 检查权限
if (!fileUserPermissionService.hasFilePermission(fileId, userId, filePermissionCheck.value())) {
throw new AccessDeniedException("Permission denied");
throw new RuntimeException("用户无操作文件和文件夹权限");
}
}
private Long resolveFileId(JoinPoint joinPoint, String expression) {
if (expression == null || expression.isEmpty()) {
// 默认:假设第一个参数是 fileIdLong 类型)
Object[] args = joinPoint.getArgs();
if (args.length > 0 && args[0] instanceof Long) {
return (Long) args[0];
}
throw new RuntimeException("未指定 fileIdExpression且第一个参数不是 Long 类型");
}
// 使用 SpEL 解析
try {
// 获取方法参数名(需要编译时保留参数名:-parameters 或 debug info
String[] paramNames = getParameterNames(joinPoint);
Object[] args = joinPoint.getArgs();
// 构建变量映射
for (int i = 0; i < paramNames.length && i < args.length; i++) {
context.setVariable(paramNames[i], args[i]);
}
Object result = parser.parseExpression(expression).getValue(context);
if (result instanceof Number) {
return ((Number) result).longValue();
} else if (result instanceof String) {
return Long.parseLong((String) result);
}
return null;
} catch (Exception e) {
throw new RuntimeException("解析 fileId 失败: " + expression, e);
}
}
// 简单方式:依赖编译参数保留形参名(推荐加 -parameters 到 javac
private String[] getParameterNames(JoinPoint joinPoint) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
return methodSignature.getParameterNames(); // 需要 JDK 8+ 且编译时加 -parameters
}
// 自定义注解用于标记需要权限检查的方法
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface FilePermissionCheck {
FilePermissionEnum value();
// 新增:指定 fileId 在哪个参数位置(从 0 开始),或通过 SpEL 表达式
// 例如: "#fileId", "#req.fileId", "#delFileReq.delFileId"
String fileIdExpression() default "";
}
}

View File

@@ -26,7 +26,6 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.util.List;
@RestController

View File

@@ -1,12 +1,14 @@
package com.sdm.data.service;
import com.sdm.common.common.SdmResponse;
import com.sdm.common.entity.enums.FilePermissionEnum;
import com.sdm.common.entity.req.data.*;
import com.sdm.common.entity.req.system.LaunchApproveReq;
import com.sdm.common.entity.resp.PageDataResp;
import com.sdm.common.entity.resp.data.BatchAddFileInfoResp;
import com.sdm.common.entity.resp.data.ChunkUploadMinioFileResp;
import com.sdm.common.entity.resp.data.FileMetadataInfoResp;
import com.sdm.data.aop.PermissionCheckAspect;
import com.sdm.data.model.req.*;
import com.sdm.data.model.resp.KKFileViewURLFromMinioResp;
import jakarta.servlet.http.HttpServletResponse;

View File

@@ -31,6 +31,7 @@ import com.sdm.common.feign.inter.system.IApproveFeignClient;
import com.sdm.common.log.CoreLogger;
import com.sdm.common.utils.*;
import com.sdm.common.utils.excel.ExcelUtil;
import com.sdm.data.aop.PermissionCheckAspect;
import com.sdm.data.model.bo.ApprovalFileDataContentsModel;
import com.sdm.data.model.entity.*;
import com.sdm.data.model.req.*;
@@ -496,7 +497,6 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService {
* @param req 创建目录请求
* @return 创建结果
*/
public SdmResponse<?> createRootDir(CreateDirReq req) {
if(ObjectUtils.isEmpty(req.getDirType())){
log.error("请选择目录类型:1 知识库文件夹2 项目节点文件夹3 头像库文件夹4 仿真参数库文件夹,5 训练模型文件夹");
@@ -839,6 +839,7 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService {
@Override
@Transactional(rollbackFor = Exception.class)
@PermissionCheckAspect.FilePermissionCheck(value = FilePermissionEnum.DELETE, fileIdExpression = "#req.delFileId")
public SdmResponse delFile(DelFileReq req) {
try {
Long delFileId = req.getDelFileId();
@@ -852,10 +853,10 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService {
String deleteFileMinioObejctKey = deleteFileMetadataInfo.getObjectKey();
boolean hasDeletePermission = fileUserPermissionService.hasFilePermission(deleteFileMetadataInfo.getId(), ThreadLocalContext.getUserId(), FilePermissionEnum.DELETE);
/*boolean hasDeletePermission = fileUserPermissionService.hasFilePermission(deleteFileMetadataInfo.getId(), ThreadLocalContext.getUserId(), FilePermissionEnum.DELETE);
if (!hasDeletePermission) {
return SdmResponse.failed("没有删除权限");
}
}*/
// 知识库
if(dirMetadataInfo!=null&&Objects.equals(DirTypeEnum.KNOWLEDGE_BASE_DIR.getValue(), dirMetadataInfo.getDirType())){
@@ -1047,6 +1048,7 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService {
@Override
@Transactional(rollbackFor = Exception.class)
@PermissionCheckAspect.FilePermissionCheck(value = FilePermissionEnum.WRITE, fileIdExpression = "#req.fileId")
public SdmResponse renameFile(RenameFileReq req) {
String oldObjectKey = null;
String newObjectKey = null;
@@ -1056,10 +1058,10 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService {
if (ObjectUtils.isEmpty(oldFile)) {
return SdmResponse.failed("文件不存在");
}
boolean hasDeletePermission = fileUserPermissionService.hasFilePermission(fileId, ThreadLocalContext.getUserId(), FilePermissionEnum.WRITE);
/*boolean hasDeletePermission = fileUserPermissionService.hasFilePermission(fileId, ThreadLocalContext.getUserId(), FilePermissionEnum.WRITE);
if (!hasDeletePermission){
return SdmResponse.failed("没有修改权限");
}
}*/
String newName = req.getNewName();
oldObjectKey = oldFile.getObjectKey();
newObjectKey = oldObjectKey.substring(0, oldObjectKey.lastIndexOf("/") + 1) + newName;
@@ -1221,6 +1223,7 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService {
}
@Override
@PermissionCheckAspect.FilePermissionCheck(value = FilePermissionEnum.DOWNLOAD, fileIdExpression = "#req.fileId")
public void downloadFile(DownloadFileReq req, HttpServletResponse response) {
try {
FileMetadataInfo fileMetadataInfo = fileMetadataInfoService.lambdaQuery().eq(FileMetadataInfo::getId, req.getFileId()).one();
@@ -1230,11 +1233,11 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService {
}
String fileObjectKey = fileMetadataInfo.getObjectKey();
boolean hasDownloadPermission = fileUserPermissionService.hasFilePermission(fileMetadataInfo.getId(), ThreadLocalContext.getUserId(), FilePermissionEnum.DOWNLOAD);
/* boolean hasDownloadPermission = fileUserPermissionService.hasFilePermission(fileMetadataInfo.getId(), ThreadLocalContext.getUserId(), FilePermissionEnum.DOWNLOAD);
if (!hasDownloadPermission) {
response.sendError(HttpServletResponse.SC_NON_AUTHORITATIVE_INFORMATION, "用户无权限");
return;
}
}*/
// 从MinIO下载文件
String encodedFileName = URLEncoder.encode(fileMetadataInfo.getOriginalName(), StandardCharsets.UTF_8);
minioService.downloadFile(fileObjectKey,response,encodedFileName,false,"");
@@ -1467,6 +1470,7 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService {
}
@Transactional(rollbackFor = Exception.class)
@PermissionCheckAspect.FilePermissionCheck(value = FilePermissionEnum.UPLOAD, fileIdExpression = "#req.id")
public SdmResponse updateFile(UpdateFileReq req) {
FileMetadataInfo fileMetadataInfo = fileMetadataInfoService.lambdaQuery().eq(FileMetadataInfo::getId, req.getId()).one();
if (fileMetadataInfo == null) {
@@ -1474,10 +1478,10 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService {
}
// 文件夹
FileMetadataInfo dirMetadataInfo = fileMetadataInfoService.lambdaQuery().eq(FileMetadataInfo::getId, fileMetadataInfo.getParentId()).eq(FileMetadataInfo::getDataType, DataTypeEnum.DIRECTORY.getValue()).one();
boolean hasUploadPermission = fileUserPermissionService.hasFilePermission(fileMetadataInfo.getId(), ThreadLocalContext.getUserId(), FilePermissionEnum.UPLOAD);
/* boolean hasUploadPermission = fileUserPermissionService.hasFilePermission(fileMetadataInfo.getId(), ThreadLocalContext.getUserId(), FilePermissionEnum.UPLOAD);
if (!hasUploadPermission) {
return SdmResponse.failed("没有更新权限");
}
}*/
String oldFileMinioObjectKey = fileMetadataInfo.getObjectKey();
Long fileGroupId = fileMetadataInfo.getFileGroupId();
Long versionNo = fileMetadataInfo.getVersionNo();