临时授权-优先取入参,其次oss默认配置过期时间

This commit is contained in:
xudawei 2024-03-21 18:08:59 +08:00
parent 0f873d6065
commit 7a3e538910
11 changed files with 111 additions and 30 deletions

View File

@ -268,7 +268,7 @@ public class WebFileController {
/** /**
* 授权给第三方下载-生成临时url * 授权给第三方下载-生成临时url
*/ */
@PostMapping(value = "/signUrl/download") @PostMapping(value = "/signUrl/fetchDownload")
@CrossOrigin @CrossOrigin
public CommonResponse<List<SignUrlDownloadResponse>> signUrlDownload(@Valid @RequestBody SignUrlDownloadDto request) { public CommonResponse<List<SignUrlDownloadResponse>> signUrlDownload(@Valid @RequestBody SignUrlDownloadDto request) {
//获取用户信息 //获取用户信息
@ -278,7 +278,7 @@ public class WebFileController {
/** /**
* 授权给第三方上传-生成临时url * 授权给第三方上传-生成临时url
*/ */
@PostMapping(value = "/signUrl/upload") @PostMapping(value = "/signUrl/fetchUpload")
@CrossOrigin @CrossOrigin
public CommonResponse<SignUrlUploadResponse> signUrlUpload(@Valid @RequestBody SignUrlUploadDto request) { public CommonResponse<SignUrlUploadResponse> signUrlUpload(@Valid @RequestBody SignUrlUploadDto request) {
ContextInfo.LiteSaasContext liteSaasContext = Objects.nonNull(ContextInfoHolder.get()) ? ContextInfoHolder.get().lite() : null; ContextInfo.LiteSaasContext liteSaasContext = Objects.nonNull(ContextInfoHolder.get()) ? ContextInfoHolder.get().lite() : null;

View File

@ -144,14 +144,6 @@ public class File extends Model<File> {
@TableField("is_delete") @TableField("is_delete")
private Integer isDelete; private Integer isDelete;
/**
* 临时授权失效时间
* 根据业务入参决定如果业务没有入参则读取file_upload_config#expiration,默认300s
*/
@TableField("expiration")
private Long expiration;
@Override @Override
protected Serializable pkVal() { protected Serializable pkVal() {
return this.id; return this.id;

View File

@ -96,6 +96,18 @@ public class FileBusinessScene extends Model<FileBusinessScene> {
@TableField("is_delete") @TableField("is_delete")
private Integer isDelete; private Integer isDelete;
/**
* 上传-临时授权失效时间,默认1800s即30分钟
*/
@TableField("upload_expiration")
private Long uploadExpiration;
/**
* 下载-临时授权失效时间,默认1800s即30分钟
*/
@TableField("download_expiration")
private Long downloadExpiration;
@Override @Override
protected Serializable pkVal() { protected Serializable pkVal() {

View File

@ -108,13 +108,6 @@ public class FileUploadConfig extends Model<FileUploadConfig> {
@TableField("is_delete") @TableField("is_delete")
private Integer isDelete; private Integer isDelete;
/**
* 临时授权失效时间,默认300s即5分钟
*/
@TableField("expiration")
private Long expiration;
@Override @Override
protected Serializable pkVal() { protected Serializable pkVal() {
return this.id; return this.id;

View File

@ -3,6 +3,8 @@ package cn.axzo.oss.dal.repository;
import cn.axzo.oss.dal.entity.FileBusinessScene; import cn.axzo.oss.dal.entity.FileBusinessScene;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/** /**
* <p> * <p>
* 文件业务场景 服务类 * 文件业务场景 服务类
@ -21,4 +23,10 @@ public interface FileBusinessSceneDao extends IService<FileBusinessScene> {
* @return * @return
*/ */
FileBusinessScene getByBucketNoAndScene(String bucketNo, String bizScene); FileBusinessScene getByBucketNoAndScene(String bucketNo, String bizScene);
/**
* 根据bucketNo与场景获取批量FileBusinessScene对象
*/
List<FileBusinessScene> queryByBucketNoAndScene(List<String> bucketNoList, String bizScen);
} }

View File

@ -5,7 +5,13 @@ import cn.axzo.oss.dal.entity.FileBusinessScene;
import cn.axzo.oss.dal.mapper.FileBusinessSceneMapper; import cn.axzo.oss.dal.mapper.FileBusinessSceneMapper;
import cn.axzo.oss.dal.repository.FileBusinessSceneDao; import cn.axzo.oss.dal.repository.FileBusinessSceneDao;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import org.springframework.util.CollectionUtils;
import java.util.Collections;
import java.util.List;
/** /**
* <p> * <p>
@ -31,4 +37,17 @@ public class FileBusinessSceneDaoImpl extends
.eq(FileBusinessScene::getBusinessScene,bizScen) .eq(FileBusinessScene::getBusinessScene,bizScen)
.eq(FileBusinessScene::getIsDelete, IsDeleteEnum.NO.getCode()).one(); .eq(FileBusinessScene::getIsDelete, IsDeleteEnum.NO.getCode()).one();
} }
/**
* 根据bucketNo与场景获取批量FileBusinessScene对象
*/
@Override
public List<FileBusinessScene> queryByBucketNoAndScene(List<String> bucketNoList, String bizScen) {
if (CollectionUtils.isEmpty(bucketNoList) || StringUtils.isBlank(bizScen)) {
return Lists.newArrayList();
}
return lambdaQuery().in(FileBusinessScene::getAppChannelBucketNo, bucketNoList)
.eq(FileBusinessScene::getBusinessScene,bizScen)
.eq(FileBusinessScene::getIsDelete, IsDeleteEnum.NO.getCode()).list();
}
} }

View File

@ -25,4 +25,9 @@ public class ApiSignUrlDownloadRequest {
@NotEmpty(message = "fileKeys not empty") @NotEmpty(message = "fileKeys not empty")
private List<String> fileKeys; private List<String> fileKeys;
/**
* bizScene,对应目录
*/
private String bizScene;
} }

View File

@ -2,6 +2,8 @@ package cn.axzo.oss.manager.api;
import cn.axzo.oss.dal.entity.FileBusinessScene; import cn.axzo.oss.dal.entity.FileBusinessScene;
import java.util.List;
/** /**
* @author: zhangran * @author: zhangran
* @date: 20210803 15:42 * @date: 20210803 15:42
@ -17,4 +19,9 @@ public interface FileBusinessSceneManager {
* @return * @return
*/ */
FileBusinessScene getByBucketNoAndScene(String bucketNo,String bizScene); FileBusinessScene getByBucketNoAndScene(String bucketNo,String bizScene);
/**
* 指定appcode文件业务场景
*/
List<FileBusinessScene> queryByBucketNoAndScene(List<String> bucketNoList, String bizScene);
} }

View File

@ -5,6 +5,7 @@ import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import java.util.List; import java.util.List;
@ -26,4 +27,9 @@ public class SignUrlDownloadDto {
@NotEmpty(message = "fileKeys not empty") @NotEmpty(message = "fileKeys not empty")
private List<String> fileKeys; private List<String> fileKeys;
/**
* bizScene,对应目录
*/
private String bizScene;
} }

View File

@ -9,6 +9,8 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.List;
/** /**
* @author: zhangran * @author: zhangran
* @date: 20210803 16:36 * @date: 20210803 16:36
@ -35,4 +37,13 @@ public class FileBusinessSceneManagerImpl implements FileBusinessSceneManager {
BizException.isEmpty(fileBusinessScene, CodeEnum.APP_CHANNEL_NOT_FOUND); BizException.isEmpty(fileBusinessScene, CodeEnum.APP_CHANNEL_NOT_FOUND);
return fileBusinessScene; return fileBusinessScene;
} }
/**
* 根据bucketNo与场景获取批量FileBusinessScene对象
*/
@Override
public List<FileBusinessScene> queryByBucketNoAndScene(List<String> bucketNoList, String bizScene) {
return fileBusinessSceneDao
.queryByBucketNoAndScene(bucketNoList, bizScene);
}
} }

View File

@ -32,6 +32,7 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import java.io.IOException; import java.io.IOException;
@ -41,6 +42,7 @@ import java.nio.file.Files;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.*; import java.util.*;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static cn.axzo.oss.common.constans.CommonConstants.APP_PRO_BUCKET_NAME; import static cn.axzo.oss.common.constans.CommonConstants.APP_PRO_BUCKET_NAME;
@ -264,9 +266,6 @@ public class FileServiceImpl implements FileService {
} }
private FileUploadConfig getFileUploadConfig(String appCode, String bizScene, Integer channelType) { private FileUploadConfig getFileUploadConfig(String appCode, String bizScene, Integer channelType) {
// 检查appCode
checkAppCode(appCode);
// 通过appcode获取文件渠道桶信息 // 通过appcode获取文件渠道桶信息
AppChannelBucket appChannelBucket = appChannelBucketManager.getByAppCode(appCode, channelType); AppChannelBucket appChannelBucket = appChannelBucketManager.getByAppCode(appCode, channelType);
@ -337,7 +336,6 @@ public class FileServiceImpl implements FileService {
ossFile.setStatus(FileStatusEnum.STATUS_UPLOAD_SUCCESS.getCode()); ossFile.setStatus(FileStatusEnum.STATUS_UPLOAD_SUCCESS.getCode());
ossFile.setFileName(fileName); ossFile.setFileName(fileName);
ossFile.setFileMd5(fileMd5); ossFile.setFileMd5(fileMd5);
ossFile.setExpiration(expiration);
fileDao.save(ossFile); fileDao.save(ossFile);
return ossFile; return ossFile;
} }
@ -737,12 +735,18 @@ public class FileServiceImpl implements FileService {
public List<SignUrlDownloadResponse> signUrlDownload(SignUrlDownloadDto dto) { public List<SignUrlDownloadResponse> signUrlDownload(SignUrlDownloadDto dto) {
log.info("signUrl download dto = {}", JsonUtil.obj2Str(dto)); log.info("signUrl download dto = {}", JsonUtil.obj2Str(dto));
List<File> fileList = fileDao.getByFileUuids(dto.getFileKeys()); List<File> fileList = fileDao.getByFileUuids(dto.getFileKeys());
if (CollectionUtils.isEmpty(fileList)) {
return Lists.newArrayList();
}
List<FileBusinessScene> fileBusinessSceneList = fileBusinessSceneManager.queryByBucketNoAndScene(fileList.stream().map(File::getAppChannelBucketNo).collect(Collectors.toList()), dto.getBizScene());
Map<String, Long> bizSceneExpireMap = fileBusinessSceneList.stream().collect(Collectors.toMap(FileBusinessScene::getAppChannelBucketNo, FileBusinessScene::getDownloadExpiration, (x, y) -> y));
return fileList.stream().map(item -> { return fileList.stream().map(item -> {
Long expire = bizSceneExpireMap.get(item.getAppChannelBucketNo());
// bucket下的key // bucket下的key
String tgtFileKey = Utility.generateFileKey(item.getDirectory(), item.getFileUuid(), item.getFileFormat()); String tgtFileKey = Utility.generateFileKey(item.getDirectory(), item.getFileUuid(), item.getFileFormat());
String signUrl = this.fileManager.signUrlDownload(item.getBucketName(), tgtFileKey, SIGN_URL_DOWNLOAD_EXPIRE_SECOND , item.getChannelCode()); String signUrl = this.fileManager.signUrlDownload(item.getBucketName(), tgtFileKey, Objects.nonNull(expire) ? expire : SIGN_URL_DOWNLOAD_EXPIRE_SECOND , item.getChannelCode());
return SignUrlDownloadResponse.builder() return SignUrlDownloadResponse.builder()
.signUrl(signUrl) .signUrl(signUrl)
.fileKey(item.getFileUuid()) .fileKey(item.getFileUuid())
@ -758,12 +762,36 @@ public class FileServiceImpl implements FileService {
log.info("signUrl upload dto = {}", JsonUtil.obj2Str(dto)); log.info("signUrl upload dto = {}", JsonUtil.obj2Str(dto));
//1 校验 //1 校验
checkAppCode(dto.getAppCode()); checkAppCode(dto.getAppCode());
//2 获取文件配置(多个配置获取优先级高)
FileUploadConfig fileUploadConfig = this.signUrlBuildUploadConfig(dto); FileUploadConfig fileUploadConfig = new FileUploadConfig();
FileBusinessScene scene = new FileBusinessScene();
if (Objects.nonNull(dto.getChannelType()) && StringUtils.isNoneBlank(dto.getBucketName()) && StringUtils.isNoneBlank(dto.getBizScene())) {
AppChannelBucket appChannelBucket = appChannelBucketManager.getByAppCodeChannelCodeBucket(dto.getAppCode(), dto.getChannelType(), dto.getBucketName());
// 通过渠道桶编码获取到具体文件业务场景
scene = fileBusinessSceneManager
.getByBucketNoAndScene(appChannelBucket.getAppChannelBucketNo(), dto.getBizScene());
// 通过渠道码和桶名称获取指定上传配置
fileUploadConfig = fileUploadConfigManager
.getByUploadConfig(scene.getAppChannelBucketNo(), scene.getDirectory());
} else {
// 通过appcode获取文件渠道桶信息
AppChannelBucket appChannelBucket = appChannelBucketManager.getByAppCode(dto.getAppCode(), dto.getChannelType());
// 通过渠道桶编码获取到具体文件业务场景
scene = fileBusinessSceneManager
.getByBucketNoAndScene(appChannelBucket.getAppChannelBucketNo(), dto.getBizScene());
// 通过渠道码和桶名称获取获取指定上传配置
fileUploadConfig = fileUploadConfigManager
.getByUploadConfig(scene.getAppChannelBucketNo(), scene.getDirectory());
}
//操作日志记录 //操作日志记录
operateLog(dto.toString(), dto.getServiceName(), FILE_UPLOAD_CODE, FILE_UPLOAD_NAME, liteSaasContext); operateLog(dto.toString(), dto.getServiceName(), FILE_UPLOAD_CODE, FILE_UPLOAD_NAME, liteSaasContext);
//3 保存File对象 //3 保存File对象
return this.signUrlSaveFile(dto, fileUploadConfig); return this.signUrlSaveFile(dto, fileUploadConfig, scene);
} }
/** /**
@ -772,7 +800,7 @@ public class FileServiceImpl implements FileService {
* @param fileUploadConfig * @param fileUploadConfig
* @return * @return
*/ */
private SignUrlUploadResponse signUrlSaveFile(SignUrlUploadDto dto, FileUploadConfig fileUploadConfig) { private SignUrlUploadResponse signUrlSaveFile(SignUrlUploadDto dto, FileUploadConfig fileUploadConfig, FileBusinessScene scene) {
String uuid = Utility.getUUID(); String uuid = Utility.getUUID();
int lastIndexOf = dto.getFileName().lastIndexOf(FileClassEnum.DOT.type); int lastIndexOf = dto.getFileName().lastIndexOf(FileClassEnum.DOT.type);
@ -790,7 +818,7 @@ public class FileServiceImpl implements FileService {
// 生成上传文件的唯一key // 生成上传文件的唯一key
String tgtFileKey = Utility.generateFileKey(fileUploadConfig.getDirectory(), uuid, fileFormat); String tgtFileKey = Utility.generateFileKey(fileUploadConfig.getDirectory(), uuid, fileFormat);
// 失效时间 // 失效时间
Long expiration = this.buildExpiration(dto, fileUploadConfig); Long expiration = this.buildExpiration(dto, scene);
//1 调用阿里云/华为云 获取临时授权signUrl //1 调用阿里云/华为云 获取临时授权signUrl
SignUrlUploadVo signUrlUpload = this.fileManager.signUrlUpload(fileUploadConfig.getBucketName(), tgtFileKey, dto.getFileName(),expiration SignUrlUploadVo signUrlUpload = this.fileManager.signUrlUpload(fileUploadConfig.getBucketName(), tgtFileKey, dto.getFileName(),expiration
, fileUploadConfig.getChannelCode(), StringUtils.isNotBlank(dto.getContentType()) ? dto.getContentType() : "multipart/form-data"); , fileUploadConfig.getChannelCode(), StringUtils.isNotBlank(dto.getContentType()) ? dto.getContentType() : "multipart/form-data");
@ -810,11 +838,11 @@ public class FileServiceImpl implements FileService {
* 临时授权失效时间 * 临时授权失效时间
* 优先从业务入参取值业务入参失效时间为空则从oss配置中取失效时间 * 优先从业务入参取值业务入参失效时间为空则从oss配置中取失效时间
*/ */
private Long buildExpiration(SignUrlUploadDto dto, FileUploadConfig fileUploadConfig) { private Long buildExpiration(SignUrlUploadDto dto, FileBusinessScene scene) {
if (Objects.nonNull(dto) && Objects.nonNull(dto.getExpiration())) { if (Objects.nonNull(dto) && Objects.nonNull(dto.getExpiration())) {
return dto.getExpiration(); return dto.getExpiration();
} }
return fileUploadConfig.getExpiration(); return scene.getUploadExpiration();
} }
/** /**