临时授权下载-加上expire

This commit is contained in:
xudawei 2024-07-04 19:23:42 +08:00
parent 0593e4dd6e
commit 73b73087bb
8 changed files with 229 additions and 11 deletions

View File

@ -14,6 +14,8 @@ import cn.axzo.oss.http.model.ApiSignUrlUploadRequest;
import cn.axzo.oss.http.model.ApiSignUrlUploadResponse; import cn.axzo.oss.http.model.ApiSignUrlUploadResponse;
import cn.axzo.oss.http.model.BatchGetObjectMetaRequest; import cn.axzo.oss.http.model.BatchGetObjectMetaRequest;
import cn.axzo.oss.http.model.BatchGetObjectMetaResponse; import cn.axzo.oss.http.model.BatchGetObjectMetaResponse;
import cn.axzo.oss.http.model.FetchUploadSignUrlToPublishRequest;
import cn.axzo.oss.http.model.FetchUploadSignUrlToPublishResponse;
import cn.axzo.oss.http.model.FileInformationResponse; import cn.axzo.oss.http.model.FileInformationResponse;
import cn.axzo.oss.http.model.FindFileKeyRequest; import cn.axzo.oss.http.model.FindFileKeyRequest;
import cn.axzo.oss.http.model.FindFileKeyResponse; import cn.axzo.oss.http.model.FindFileKeyResponse;
@ -42,8 +44,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -223,4 +223,15 @@ public class ServerFileController implements ServerFileServiceApi {
ContextInfo.LiteSaasContext liteSaasContext = JSONUtil.toBean(contextInfoLiteJsonStr, ContextInfo.LiteSaasContext.class); ContextInfo.LiteSaasContext liteSaasContext = JSONUtil.toBean(contextInfoLiteJsonStr, ContextInfo.LiteSaasContext.class);
return CommonResponse.success(BeanConverter.convert(fileByUrlService.uploadByUrl(dto.getAppCode(), dto.getBizScene(), dto.getFileName(), dto.getFileUrl(), dto.getChannelCode(), dto.getStyle(), liteSaasContext), ServerFileUploadResponse.class)); return CommonResponse.success(BeanConverter.convert(fileByUrlService.uploadByUrl(dto.getAppCode(), dto.getBizScene(), dto.getFileName(), dto.getFileUrl(), dto.getChannelCode(), dto.getStyle(), liteSaasContext), ServerFileUploadResponse.class));
} }
/**
* 临时授权上传-生成临时url-公有桶
*/
@Override
public CommonResponse<FetchUploadSignUrlToPublishResponse> fetchUploadSignUrlToPublish(@Valid @RequestBody FetchUploadSignUrlToPublishRequest request) {
SignUrlUploadDto dto = BeanConvertUtil.copyBean(request, SignUrlUploadDto.class);
dto.setAppCode(dto.getAppCode() + "-public");
dto.setBizScene(dto.getAppCode() + "-public");
return CommonResponse.success(BeanConverter.convert(fileService.signUrlUpload(dto, ContextInfo.LiteSaasContext.builder().build()), FetchUploadSignUrlToPublishResponse.class));
}
} }

View File

@ -6,6 +6,8 @@ import cn.axzo.oss.http.model.ApiSignUrlUploadRequest;
import cn.axzo.oss.http.model.ApiSignUrlUploadResponse; import cn.axzo.oss.http.model.ApiSignUrlUploadResponse;
import cn.axzo.oss.http.model.BatchGetObjectMetaRequest; import cn.axzo.oss.http.model.BatchGetObjectMetaRequest;
import cn.axzo.oss.http.model.BatchGetObjectMetaResponse; import cn.axzo.oss.http.model.BatchGetObjectMetaResponse;
import cn.axzo.oss.http.model.FetchUploadSignUrlToPublishRequest;
import cn.axzo.oss.http.model.FetchUploadSignUrlToPublishResponse;
import cn.axzo.oss.http.model.FileInformationResponse; import cn.axzo.oss.http.model.FileInformationResponse;
import cn.axzo.oss.http.model.FindFileKeyRequest; import cn.axzo.oss.http.model.FindFileKeyRequest;
import cn.axzo.oss.http.model.FindFileKeyResponse; import cn.axzo.oss.http.model.FindFileKeyResponse;
@ -117,4 +119,10 @@ public interface ServerFileServiceApi {
@RequestMapping(value = "/api/v1/server/uploadByUrl", method = RequestMethod.POST) @RequestMapping(value = "/api/v1/server/uploadByUrl", method = RequestMethod.POST)
CommonResponse<ServerFileUploadResponse> uploadByUrl(ServerFileUploadByUrlRequest request); CommonResponse<ServerFileUploadResponse> uploadByUrl(ServerFileUploadByUrlRequest request);
/**
* 临时授权上传-生成临时url-公有桶
*/
@RequestMapping(value = "/api/v1/server/fetchUploadToPublishSignUrl", method = RequestMethod.POST)
CommonResponse<FetchUploadSignUrlToPublishResponse> fetchUploadSignUrlToPublish(@Valid @RequestBody FetchUploadSignUrlToPublishRequest request);
} }

View File

@ -47,4 +47,9 @@ public class ApiSignUrlDownloadRequest {
*/ */
private Boolean hasFileName = true; private Boolean hasFileName = true;
/**
* 过期时间
*/
private Long expiration;
} }

View File

@ -0,0 +1,68 @@
package cn.axzo.oss.http.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
/**
* @author: xudawei
* @date: 2024-03-12
* @description: 授权给第三方下载
**/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class FetchUploadSignUrlToPublishRequest {
/**
* appCode
*/
@NotBlank(message = "appCode not blank")
private String appCode;
/**
* bizScene,对应目录
*/
@NotBlank(message = "bizScene not blank")
private String bizScene;
/**
* serviceName
*/
private String serviceName;
/**
* 1-阿里云-aliyun
* 2-华为云-huaweicloud
*/
private Integer channelType;
/**
* 桶名称
*/
private String bucketName;
/**
* 文件名称
*/
private String fileName;
/**
* 类型
*/
private String contentType = "multipart/form-data";
/**
* 过期时间
*/
private Long expiration;
/**
* 是否带上文件名称
*/
private Boolean hasFileName = true;
/**
* 桶key
*/
private String bucketKey;
}

View File

@ -0,0 +1,54 @@
package cn.axzo.oss.http.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @Author: xudawei
* @Date: 2024/03/12
* @Description: 授权给第三方下载
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class FetchUploadSignUrlToPublishResponse {
/**
* 文件临时-URL
*/
private String signUrl;
/**
* 文件 Key
*/
private String fileKey;
/**
* host
*/
private String host;
/**
* 类型
*/
private String contentType;
/**
* 通道
* 1-阿里云-aliyun
* 2-华为云-huaweicloud
*/
private String channelCode;
/**
* 下载url
*/
private String downloadSignUrl;
/**
* 文件名称
*/
private String fileName;
}

View File

@ -0,0 +1,64 @@
package cn.axzo.oss.manager.api.dto.request;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author: xudawei
* @date: 2024-03-12
* @description: 授权给第三方下载
**/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class FetchUploadSignUrlToPublishDto {
/**
* appCode
*/
private String appCode;
/**
* bizScene,对应目录
*/
private String bizScene;
/**
* serviceName
*/
private String serviceName;
/**
* 1-阿里云-aliyun
* 2-华为云-huaweicloud
*/
private Integer channelType;
/**
* 桶名称
*/
private String bucketName;
/**
* 文件名称
*/
private String fileName;
/**
* 类型
*/
private String contentType = "multipart/form-data";
/**
* 过期时间
*/
private Long expiration;
/**
* 是否带上文件名称
*/
private Boolean hasFileName = true;
/**
* 桶key
*/
private String bucketKey;
}

View File

@ -45,4 +45,9 @@ public class SignUrlDownloadDto {
*/ */
private Boolean hasFileName = true; private Boolean hasFileName = true;
/**
* 过期时间
*/
private Long expiration;
} }

View File

@ -850,7 +850,7 @@ public class FileServiceImpl implements FileService {
List<SignUrlDownloadResponse> httpUrlSignResList = this.buildHttpUrlSignResponse(dto); List<SignUrlDownloadResponse> httpUrlSignResList = this.buildHttpUrlSignResponse(dto);
//3 构建fileKey入参对象集合 //3 构建fileKey入参对象集合
List<SignUrlDownloadResponse> fileKeyResList = this.buildFileKeyResponse(dto.getFileKeys(), dto.getBizScene(), dto.getStyle(), dto.getHasFileName()); List<SignUrlDownloadResponse> fileKeyResList = this.buildFileKeyResponse(dto.getFileKeys(), dto.getBizScene(), dto.getStyle(), dto.getHasFileName(), dto.getExpiration());
//4 1/2/3集合累加 //4 1/2/3集合累加
httpUrlResList.addAll(fileKeyResList); httpUrlResList.addAll(fileKeyResList);
httpUrlResList.addAll(httpUrlSignResList); httpUrlResList.addAll(httpUrlSignResList);
@ -861,7 +861,7 @@ public class FileServiceImpl implements FileService {
/** /**
* 构建fileKey(非http的入参)的返回对象 * 构建fileKey(非http的入参)的返回对象
*/ */
private List<SignUrlDownloadResponse> buildFileKeyResponse(List<String> fileKeys, String bizScene, String style, boolean hasFileName) { private List<SignUrlDownloadResponse> buildFileKeyResponse(List<String> fileKeys, String bizScene, String style, boolean hasFileName, Long expiration) {
if (CollectionUtil.isEmpty(fileKeys)) { if (CollectionUtil.isEmpty(fileKeys)) {
return Lists.newArrayList(); return Lists.newArrayList();
} }
@ -882,15 +882,15 @@ public class FileServiceImpl implements FileService {
List<FileBusinessScene> fileBusinessSceneList = fileBusinessSceneManager.queryByBucketNoAndScene(fileList.stream().map(File::getAppChannelBucketNo).collect(Collectors.toSet()), bizScene); List<FileBusinessScene> fileBusinessSceneList = fileBusinessSceneManager.queryByBucketNoAndScene(fileList.stream().map(File::getAppChannelBucketNo).collect(Collectors.toSet()), bizScene);
Map<String, Long> bizSceneExpireMap = fileBusinessSceneList.stream().collect(Collectors.toMap(FileBusinessScene::getAppChannelBucketNo, FileBusinessScene::getDownloadExpiration, (x, y) -> y)); Map<String, Long> bizSceneExpireMap = fileBusinessSceneList.stream().collect(Collectors.toMap(FileBusinessScene::getAppChannelBucketNo, FileBusinessScene::getDownloadExpiration, (x, y) -> y));
//构建返回集合 //构建返回集合
return this.buildFileKeyRespByFile(fileList, bucketTypeMap, bizSceneExpireMap, style, hasFileName); return this.buildFileKeyRespByFile(fileList, bucketTypeMap, bizSceneExpireMap, style, hasFileName, expiration);
} }
/** /**
* 通过File对象构建返回集合 * 通过File对象构建返回集合
*/ */
private List<SignUrlDownloadResponse> buildFileKeyRespByFile(List<File> fileList,Map<String, String> bucketTypeMap, Map<String, Long> bizSceneExpireMap, String style, boolean hasFileName) { private List<SignUrlDownloadResponse> buildFileKeyRespByFile(List<File> fileList,Map<String, String> bucketTypeMap, Map<String, Long> bizSceneExpireMap, String style, boolean hasFileName, Long expiration) {
List<SignUrlDownloadResponse> responseList = fileList.stream().map(item -> { List<SignUrlDownloadResponse> responseList = fileList.stream().map(item -> {
Long expire = bizSceneExpireMap.get(item.getAppChannelBucketNo()); Long expire = Objects.nonNull(expiration) ? expiration : 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 bucketType = StringUtils.isNotBlank(bucketTypeMap.get(item.getAppChannelBucketNo())) ? bucketTypeMap.get(item.getAppChannelBucketNo()) : BucketTypeEnum.PRIVATE_BUCKET.getCode(); String bucketType = StringUtils.isNotBlank(bucketTypeMap.get(item.getAppChannelBucketNo())) ? bucketTypeMap.get(item.getAppChannelBucketNo()) : BucketTypeEnum.PRIVATE_BUCKET.getCode();
@ -995,7 +995,7 @@ public class FileServiceImpl implements FileService {
if (CollectionUtil.isEmpty(map)) { if (CollectionUtil.isEmpty(map)) {
return httpUrlList.stream().map(item -> SignUrlDownloadResponse.builder().fileKey(item).signUrl(item).build()).collect(Collectors.toList()); return httpUrlList.stream().map(item -> SignUrlDownloadResponse.builder().fileKey(item).signUrl(item).build()).collect(Collectors.toList());
} }
List<SignUrlDownloadResponse> responseList = this.buildFileKeyResponse(Lists.newArrayList(map.values()), null, dto.getStyle(), dto.getHasFileName()); List<SignUrlDownloadResponse> responseList = this.buildFileKeyResponse(Lists.newArrayList(map.values()), null, dto.getStyle(), dto.getHasFileName(), dto.getExpiration());
if (CollectionUtil.isEmpty(responseList)) { if (CollectionUtil.isEmpty(responseList)) {
return httpUrlList.stream().map(item -> SignUrlDownloadResponse.builder().fileKey(item).signUrl(item).build()).collect(Collectors.toList()); return httpUrlList.stream().map(item -> SignUrlDownloadResponse.builder().fileKey(item).signUrl(item).build()).collect(Collectors.toList());
} }
@ -1024,12 +1024,13 @@ public class FileServiceImpl implements FileService {
* 从链接中提取fileKey比如如下链接获取fileKey:b4148fbee6954c2fa3139471f18a2dcd * 从链接中提取fileKey比如如下链接获取fileKey:b4148fbee6954c2fa3139471f18a2dcd
* https://xx/identity/b4148fbee6954c2fa3139471f18a2dcd.jpg?AccessKeyId=xx&Expires=xx&response-content-disposition=xx&Signature=xx * https://xx/identity/b4148fbee6954c2fa3139471f18a2dcd.jpg?AccessKeyId=xx&Expires=xx&response-content-disposition=xx&Signature=xx
*/ */
private String signUrlToFileKey(String signUrl) { public static String signUrlToFileKey(String signUrl) {
if (StringUtils.isBlank(signUrl)) { if (StringUtils.isBlank(signUrl)) {
return StringUtils.EMPTY; return StringUtils.EMPTY;
} }
if (signUrl.contains("/") && signUrl.contains("?")) { if (signUrl.contains("/") && signUrl.contains("?")) {
String fileName = signUrl.substring(signUrl.lastIndexOf("/") + 1, signUrl.indexOf("?")); signUrl = signUrl.split("\\?")[0];
String fileName = signUrl.substring(signUrl.lastIndexOf("/") + 1);
if (fileName.contains(".")) { if (fileName.contains(".")) {
return fileName.substring(0, fileName.indexOf(".")); return fileName.substring(0, fileName.indexOf("."));
} }
@ -1127,6 +1128,7 @@ public class FileServiceImpl implements FileService {
*/ */
@Override @Override
public List<SignUrlDownloadResponse> signUrlDownloadNoFile(SignUrlDownloadDto dto) { public List<SignUrlDownloadResponse> signUrlDownloadNoFile(SignUrlDownloadDto dto) {
// 通过appcode获取文件渠道桶信息 // 通过appcode获取文件渠道桶信息
AppChannelBucket appChannelBucket = appChannelBucketManager.getByAppCode(dto.getAppCode(), null); AppChannelBucket appChannelBucket = appChannelBucketManager.getByAppCode(dto.getAppCode(), null);
@ -1134,10 +1136,11 @@ public class FileServiceImpl implements FileService {
FileBusinessScene scene = fileBusinessSceneManager FileBusinessScene scene = fileBusinessSceneManager
.getByBucketNoAndScene(appChannelBucket.getAppChannelBucketNo(), dto.getBizScene()); .getByBucketNoAndScene(appChannelBucket.getAppChannelBucketNo(), dto.getBizScene());
Long expiration = Objects.nonNull(dto.getExpiration()) ? dto.getExpiration() : scene.getDownloadExpiration();
return dto.getFileKeys().stream().map(item ->{ return dto.getFileKeys().stream().map(item ->{
//构建返回集合 //构建返回集合
return this.buildSignUrlDownloadResponse(appChannelBucket.getBucketType(), appChannelBucket.getBucketName() return this.buildSignUrlDownloadResponse(appChannelBucket.getBucketType(), appChannelBucket.getBucketName()
, item, appChannelBucket.getChannelCode(), item, scene.getDownloadExpiration()); , item, appChannelBucket.getChannelCode(), item, expiration);
}).collect(Collectors.toList()); }).collect(Collectors.toList());
} }