From 997fab49917cb3e4fef95d47f4ca116161f3dab8 Mon Sep 17 00:00:00 2001 From: duandazhi Date: Wed, 18 Aug 2021 10:07:34 +0800 Subject: [PATCH] =?UTF-8?q?ruoyi-file=20=E5=A2=9E=E5=8A=A0=20=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E5=8A=A0=E7=AD=BE=E7=9A=84url=20=EF=BC=88getPresigned?= =?UTF-8?q?Url=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ruoyi/system/api/RemoteFileService.java | 11 ++- .../factory/RemoteFileFallbackFactory.java | 7 +- ruoyi-modules/ruoyi-file/pom.xml | 28 ++++--- .../com/ruoyi/file/config/FastDfsConfig.java | 53 +++++++++++++ .../com/ruoyi/file/config/MinioConfig.java | 51 ++++++++++++ .../ruoyi/file/config/ResourcesConfig.java | 8 +- .../file/controller/SysFileController.java | 23 +++++- .../service/FastDfsSysFileServiceImpl.java | 46 ++++++++--- .../ruoyi/file/service/ISysFileService.java | 21 ++++- .../file/service/LocalSysFileServiceImpl.java | 11 ++- .../file/service/MinioSysFileServiceImpl.java | 77 ++++++++++++++++++- 11 files changed, 302 insertions(+), 34 deletions(-) create mode 100644 ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/config/FastDfsConfig.java diff --git a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/RemoteFileService.java b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/RemoteFileService.java index ae56a54a..bee3c6e3 100644 --- a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/RemoteFileService.java +++ b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/RemoteFileService.java @@ -2,7 +2,9 @@ package com.ruoyi.system.api; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.multipart.MultipartFile; import com.ruoyi.common.core.constant.ServiceNameConstants; @@ -12,7 +14,7 @@ import com.ruoyi.system.api.factory.RemoteFileFallbackFactory; /** * 文件服务 - * + * * @author ruoyi */ @FeignClient(contextId = "remoteFileService", value = ServiceNameConstants.FILE_SERVICE, fallbackFactory = RemoteFileFallbackFactory.class) @@ -26,4 +28,11 @@ public interface RemoteFileService */ @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public R upload(@RequestPart(value = "file") MultipartFile file); + + /** + * 临时安全凭证、获取加签的url; 根据输入的url,获取带有临时安全凭证的url + * @param fileUrl 待加签的url + */ + @GetMapping("getPresignedUrl") + R getPresignedUrl(@RequestParam(value = "fileUrl") String fileUrl); } diff --git a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/RemoteFileFallbackFactory.java b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/RemoteFileFallbackFactory.java index bc3b6fff..a24298b1 100644 --- a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/RemoteFileFallbackFactory.java +++ b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/RemoteFileFallbackFactory.java @@ -11,7 +11,7 @@ import com.ruoyi.system.api.domain.SysFile; /** * 文件服务降级处理 - * + * * @author ruoyi */ @Component @@ -30,6 +30,11 @@ public class RemoteFileFallbackFactory implements FallbackFactory getPresignedUrl(String fileUrl) { + return R.fail("文件加签失败:" + throwable.getMessage()); + } }; } } diff --git a/ruoyi-modules/ruoyi-file/pom.xml b/ruoyi-modules/ruoyi-file/pom.xml index 9a6cb51b..58101b10 100644 --- a/ruoyi-modules/ruoyi-file/pom.xml +++ b/ruoyi-modules/ruoyi-file/pom.xml @@ -16,56 +16,62 @@ - + com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery - + com.alibaba.cloud spring-cloud-starter-alibaba-nacos-config - + com.alibaba.cloud spring-cloud-starter-alibaba-sentinel - + org.springframework.boot spring-boot-starter-actuator - + com.github.tobato fastdfs-client - + + + net.oschina.zcx7878 + fastdfs-client-java + 1.27.0.0 + + io.minio minio ${minio.version} - + com.ruoyi ruoyi-api-system - + com.ruoyi ruoyi-common-swagger - + @@ -84,5 +90,5 @@ - - \ No newline at end of file + + diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/config/FastDfsConfig.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/config/FastDfsConfig.java new file mode 100644 index 00000000..e9f3194d --- /dev/null +++ b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/config/FastDfsConfig.java @@ -0,0 +1,53 @@ +package com.ruoyi.file.config; + +import com.github.tobato.fastdfs.FdfsClientConstants; +import com.github.tobato.fastdfs.domain.conn.PooledConnectionFactory; +import com.ruoyi.file.service.FastDfsSysFileServiceImpl; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.context.annotation.Configuration; + +/** + * 阿里 fastdfs 配置 + * @author dazer + * @see FastDfsSysFileServiceImpl + * FastDFS配置 其他参数见:{@link PooledConnectionFactory} + * + * 使用: Docker部署FastDFS(附示例代码) https://www.cnblogs.com/cao-lei/p/13470695.html + * github 地址:https://github.com/tobato/FastDFS_Client + */ +@RefreshScope +@Configuration +@ConfigurationProperties( + prefix = FdfsClientConstants.ROOT_CONFIG_PREFIX +) +public class FastDfsConfig { + /** + * 文件对外访问域名or ip + * FastDFS配置 其他参数见:{@link PooledConnectionFactory} + * //@Value("${fdfs.domain}") + */ + private String domain; + + /** + * 生成防盗链token的加密key;注意保密 + * fastdfs 内置的功能,需要和 FastDFS 【etc/fdfs/http.conf】 【http.anti_steal.secret_key】保持一致 + */ + private String tokenSecretKey; + + public String getDomain() { + return domain; + } + + public void setDomain(String domain) { + this.domain = domain; + } + + public String getTokenSecretKey() { + return tokenSecretKey; + } + + public void setTokenSecretKey(String tokenSecretKey) { + this.tokenSecretKey = tokenSecretKey; + } +} diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/config/MinioConfig.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/config/MinioConfig.java index ee3e14c2..3718e9ce 100644 --- a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/config/MinioConfig.java +++ b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/config/MinioConfig.java @@ -1,6 +1,7 @@ package com.ruoyi.file.config; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import io.minio.MinioClient; @@ -10,6 +11,7 @@ import io.minio.MinioClient; * * @author ruoyi */ +@RefreshScope @Configuration @ConfigurationProperties(prefix = "minio") public class MinioConfig @@ -34,6 +36,30 @@ public class MinioConfig */ private String bucketName; + /** + * 访问域名; url经常是内网地址,外部访问用域名或者外网ip + * eg: https://yq666.bj.gov.cn/appt-file + * + * 注意!!:minio要配置 Bucket Policy: Bucket ==> Edit Bucket + * 1、Read Only + * 2、Write Only + * 3、Read and Write + * 4、不做任何分配 【必须要加签之后才能访问】 + */ + private String domain; + + /** + * 过期时间 + * 文档:MinIO STS快速入门指南 http://docs.minio.org.cn/docs/master/minio-sts-quickstart-guide + * 文档:适用于与Amazon S3兼容的云存储的MinIO Java SDK: API文档: Presigned操作: presignedGetObject: http://docs.minio.org.cn/docs/master/java-client-quickstart-guide + * 默认7天,单位秒; + * 1小时:3600 = 60 * 60 * 1 + * 24小时(1天):86400 = 60 * 60 * 24 + * 7天:604800 = 86400 * 7 + * -1: 就永不过期,原样返回url + */ + private Integer expiryDuration = 86400; + public String getUrl() { return url; @@ -74,6 +100,31 @@ public class MinioConfig this.bucketName = bucketName; } + public String getDomain() { + return domain; + } + + public void setDomain(String domain) { + this.domain = domain; + } + + public Integer getExpiryDuration() { + if (expiryDuration == null) { + // 默认一个小时, 3600秒 + expiryDuration = 86400; + } + if (expiryDuration < 1L && expiryDuration != -1) { + // 最小1秒 + // 如果要永不过期,就不要调用 -1; 直接原样返回 + expiryDuration = 1; + } + return expiryDuration; + } + + public void setExpiryDuration(Integer expiryDuration) { + this.expiryDuration = expiryDuration; + } + @Bean public MinioClient getMinioClient() { diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/config/ResourcesConfig.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/config/ResourcesConfig.java index 3bca6686..f5ea3407 100644 --- a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/config/ResourcesConfig.java +++ b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/config/ResourcesConfig.java @@ -2,6 +2,7 @@ package com.ruoyi.file.config; import java.io.File; import org.springframework.beans.factory.annotation.Value; +import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; @@ -9,9 +10,10 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** * 通用映射配置 - * + * * @author ruoyi */ +@RefreshScope @Configuration public class ResourcesConfig implements WebMvcConfigurer { @@ -34,7 +36,7 @@ public class ResourcesConfig implements WebMvcConfigurer registry.addResourceHandler(localFilePrefix + "/**") .addResourceLocations("file:" + localFilePath + File.separator); } - + /** * 开启跨域 */ @@ -47,4 +49,4 @@ public class ResourcesConfig implements WebMvcConfigurer // 设置允许的方法 .allowedMethods("GET"); } -} \ No newline at end of file +} diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/controller/SysFileController.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/controller/SysFileController.java index 318db416..6e9c49d9 100644 --- a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/controller/SysFileController.java +++ b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/controller/SysFileController.java @@ -1,9 +1,13 @@ package com.ruoyi.file.controller; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import com.ruoyi.common.core.domain.R; @@ -13,7 +17,7 @@ import com.ruoyi.system.api.domain.SysFile; /** * 文件请求处理 - * + * * @author ruoyi */ @RestController @@ -45,4 +49,19 @@ public class SysFileController return R.fail(e.getMessage()); } } -} \ No newline at end of file + + /** + * 对访问url进行签名加密 别名 【临时安全凭证】 + * 兼容 AWS Security Token Service (STS) 的联合身份临时安全凭证 (federation token) ,更多详细信息请查阅 + * aliyun oss 实例: http://react-yuebaoxiao-pro.oss-cn-shanghai.aliyuncs.com/dev/upload/default/20210719-23d31398-4849-408d-8775-a5b668ccafc3.jpeg?Expires=1626736182&OSSAccessKeyId=LTAI4GDQSbwgmbsRxxbDXnKT&Signature=P3w3%2FIpEnZEUhYku6scOos4p54A%3D + * minio 示例: https://yq666.bj.gov.cn/appt-file/dev/default/2021/07/19/5fe1478b-969c-4b6e-9cc0-742412dc3128.jpeg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=D99KGE6ZTQXSATTJWU24%2F20210719%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20210719T112025Z&X-Amz-Expires=432000&X-Amz-SignedHeaders=host&X-Amz-Signature=e45171d0885f006ee1de43cec9d88963e2b55c6e671740ae5695410ba16770c5 + * --------------------------------------------------- + * 【说明】文件服务器,一般默认是不加延签参数就可以访问,要让验签看到效果,一般都需要在 对应文件服务器 bucket 上面做访问策略的配置 + */ + @ApiOperation(value = "临时安全凭证、获取加签的url", notes = "根据输入的url,获取带有临时安全凭证的url") + @GetMapping("getPresignedUrl") + public R getPresignedUrl( + @ApiParam("需要访问的url,字段名:fileUrl,必填;不要带有?后面的参数") @RequestParam(value = "fileUrl") String fileUrl) { + return R.ok(sysFileService.presignedUrl(fileUrl), "获取成功"); + } +} diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/FastDfsSysFileServiceImpl.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/FastDfsSysFileServiceImpl.java index deee22ee..771dbc04 100644 --- a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/FastDfsSysFileServiceImpl.java +++ b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/FastDfsSysFileServiceImpl.java @@ -1,8 +1,12 @@ package com.ruoyi.file.service; +import com.ruoyi.common.core.constant.HttpStatus; +import com.ruoyi.common.core.exception.file.FileException; +import com.ruoyi.file.config.FastDfsConfig; import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang3.StringUtils; +import org.csource.fastdfs.ProtoCommon; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import com.github.tobato.fastdfs.domain.fdfs.StorePath; @@ -10,24 +14,21 @@ import com.github.tobato.fastdfs.service.FastFileStorageClient; /** * FastDFS 文件存储 - * + * * @author ruoyi */ @Service public class FastDfsSysFileServiceImpl implements ISysFileService { - /** - * 域名或本机访问地址 - */ - @Value("${fdfs.domain}") - public String domain; + @Autowired + private FastDfsConfig fastDfsConfig; @Autowired private FastFileStorageClient storageClient; /** * FastDfs文件上传接口 - * + * * @param file 上传的文件 * @return 访问地址 * @throws Exception @@ -37,6 +38,33 @@ public class FastDfsSysFileServiceImpl implements ISysFileService { StorePath storePath = storageClient.uploadFile(file.getInputStream(), file.getSize(), FilenameUtils.getExtension(file.getOriginalFilename()), null); - return domain + "/" + storePath.getFullPath(); + // 形如: http://47.99.175.191:8888/group1/M00/00/00/rBzzjWD-ec2ADLS9AAJiu1rRenk51.jpeg + return fastDfsConfig.getDomain() + "/" + storePath.getFullPath(); + } + + @Override + public String presignedUrl(String fileUrl) { + if (StringUtils.isBlank(fastDfsConfig.getTokenSecretKey())) { + throw new FileException(HttpStatus.ERROR + "", new String[] {"防盗链生成token的密钥为空,请检查:tokenSecretKey"}); + } + String signKey = "?token="; + if (fileUrl.contains(signKey)) { + return fileUrl; + } + String tokenSecretKey = fastDfsConfig.getTokenSecretKey(); + + StorePath storePath = StorePath.parseFromUrl(fileUrl); + String keyPath = storePath.getPath(); + //时间戳 单位为秒 + int ts = (int) (System.currentTimeMillis() / 1000); + + String token; + try { + token = ProtoCommon.getToken(keyPath, ts, tokenSecretKey); + } catch (Exception e) { + throw new FileException(HttpStatus.ERROR + "", new String[] {"FastDFS获取token异常"}); + } + // 形如: http://47.99.175.191:8888/group1/M00/00/00/rBzzjWD-ec2ADLS9AAJiu1rRenk51.jpeg + return fastDfsConfig.getDomain() + "/" + storePath.getFullPath() + "?token=" + token + "&ts=" + ts; } } diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/ISysFileService.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/ISysFileService.java index 5a353489..2b613b2a 100644 --- a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/ISysFileService.java +++ b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/ISysFileService.java @@ -4,17 +4,34 @@ import org.springframework.web.multipart.MultipartFile; /** * 文件上传接口 - * + * * @author ruoyi */ public interface ISysFileService { /** * 文件上传接口 - * + * * @param file 上传的文件 * @return 访问地址 * @throws Exception */ public String uploadFile(MultipartFile file) throws Exception; + + /** + * 对访问url进行签名加密 别名 【临时安全凭证】 + * 兼容 AWS Security Token Service (STS) 的联合身份临时安全凭证 (federation token) ,更多详细信息请查阅 + * + * 1、aliyun oss 叫做;STS服务 临时安全令牌(Security Token Service,STS) 说明:https://help.aliyun.com/document_detail/28761.html?spm=a2c4g.11186623.6.880.22bd2fe5pL1d39 + * 2、minio 叫做;resignedGetObject 临时安全令牌(Security Token Service,STS); 【Presigned presignedGetObject 预签】 + * http://docs.minio.org.cn/docs/master/minio-sts-quickstart-guide + * minio SDKS Java Client API参考文档 http://docs.minio.org.cn/docs/master/java-client-api-reference + * 3、qiniu ;七牛云存储; 下载凭证(如果Bucket设置成私有,必须要有 下载凭证),路径:【对象存储==》使用指南===》安全机制===》 下载凭证】 https://developer.qiniu.com/kodo/1202/download-token + * https://developer.qiniu.com/kodo/5914/s3-compatible-sts + * 4、腾讯 临时密钥(临时访问凭证) GetFederationToken 临时密钥生成及使用指引 https://cloud.tencent.com/document/product/436/14048?from=10680 + * 5、fastdfs 防掉链 前提,需要在 fastdfs上面配置 https://www.cnblogs.com/xiaolinstudy/p/9341779.html + * @param fileUrl 文件访问地址,全路径或者不是全路径都可以 + * @return 返回签名后的url + */ + String presignedUrl(String fileUrl); } diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/LocalSysFileServiceImpl.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/LocalSysFileServiceImpl.java index c0e20681..7b3e43a7 100644 --- a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/LocalSysFileServiceImpl.java +++ b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/LocalSysFileServiceImpl.java @@ -8,7 +8,7 @@ import com.ruoyi.file.utils.FileUploadUtils; /** * 本地文件存储 - * + * * @author ruoyi */ @Primary @@ -26,7 +26,7 @@ public class LocalSysFileServiceImpl implements ISysFileService */ @Value("${file.domain}") public String domain; - + /** * 上传文件存储在本地的根路径 */ @@ -35,7 +35,7 @@ public class LocalSysFileServiceImpl implements ISysFileService /** * 本地文件上传接口 - * + * * @param file 上传的文件 * @return 访问地址 * @throws Exception @@ -47,4 +47,9 @@ public class LocalSysFileServiceImpl implements ISysFileService String url = domain + localFilePrefix + name; return url; } + + @Override + public String presignedUrl(String fileUrl) { + return fileUrl; + } } diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/MinioSysFileServiceImpl.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/MinioSysFileServiceImpl.java index 3dd2fc6f..3a2cbbae 100644 --- a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/MinioSysFileServiceImpl.java +++ b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/MinioSysFileServiceImpl.java @@ -1,5 +1,8 @@ package com.ruoyi.file.service; +import io.minio.GetPresignedObjectUrlArgs; +import io.minio.errors.*; +import io.minio.http.Method; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; @@ -8,10 +11,24 @@ import com.ruoyi.file.utils.FileUploadUtils; import io.minio.MinioClient; import io.minio.PutObjectArgs; +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.concurrent.TimeUnit; + /** * Minio 文件存储 - * + * * @author ruoyi + * 官网博客: http://docs.minio.org.cn/docs/master/java-client-quickstart-guidec + * 在springboot中使用Minio8 https://springboot.io/t/topic/3109 + * 1、上传操作:putObject + * 2、删除操作:removeObject + * ================== + * 3、预签(Presigned)操作:【设置访问过期时间】:【支持对url进行鉴权:【sts】【临时授权】】presignedGetObject + * presignedGetObject(String bucketName, String objectName, Integer expires) + * http://docs.minio.org.cn/docs/master/java-client-api-reference#presignedGetObject + * MinIO STS快速入门指南 http://docs.minio.org.cn/docs/master/minio-sts-quickstart-guide */ @Service public class MinioSysFileServiceImpl implements ISysFileService @@ -24,7 +41,7 @@ public class MinioSysFileServiceImpl implements ISysFileService /** * 本地文件上传接口 - * + * * @param file 上传的文件 * @return 访问地址 * @throws Exception @@ -42,4 +59,60 @@ public class MinioSysFileServiceImpl implements ISysFileService client.putObject(args); return minioConfig.getUrl() + "/" + minioConfig.getBucketName() + "/" + fileName; } + + /** + * 给原始的URL add 过期时间 + * [STS 临时授权] + * http://docs.minio.org.cn/docs/master/minio-sts-quickstart-guide + * minio SDKS Java Client API参考文档 http://docs.minio.org.cn/docs/master/java-client-api-reference + * Presigned presignedGetObject 预签】 + * 示例:https://xxxx.xxx.gov.cn/file/2021/08/06/cd9dfbaa-8563-423a-bc3d-d0b15e781931.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=D99KGE6ZTQXSATTJWU24%2F20210809%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20210809T075702Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host&X-Amz-Signature=198c76edc57998f4dde72124952b43f0066c762356e485dd44d21df9cc7dad78 + */ + @Override + public String presignedUrl(String fileUrl) { + if (minioConfig.getExpiryDuration() == -1) { + return fileUrl; + } + String signKey = "?X-Amz-Algorithm="; + if (fileUrl.contains(signKey)) { + return fileUrl; + } + String objectName = this.getStorePath(fileUrl); + GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder(). + bucket(minioConfig.getBucketName()). + method(Method.GET). + object(objectName). + expiry(minioConfig.getExpiryDuration(), TimeUnit.SECONDS).build(); + + String presignedObjectUrl = null; + try { + presignedObjectUrl = client.getPresignedObjectUrl(args); + String basePrivateUrl = minioConfig.getUrl() + "/" + minioConfig.getBucketName() + "/"; + presignedObjectUrl = presignedObjectUrl.replace(basePrivateUrl, ""); + } catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | XmlParserException | ServerException e) { + e.printStackTrace(); + presignedObjectUrl = fileUrl; + } + return minioConfig.getDomain() + "/" + minioConfig.getBucketName() + "/" + presignedObjectUrl; + } + + /** + * 转换url,为原始的key + * + * @param filePath https://yq666.bj.gov.cn/appt-file/dev/default/2021/07/18/f4243eb2-06a1-4304-bdfc-e2964b8721bb.jpeg + * @return dev/default/2021/07/18/f4243eb2-06a1-4304-bdfc-e2964b8721bb.jpeg + */ + private String getStorePath(String filePath) { + String oldPath = filePath; + // 处理方式1 + String publicPath3 = minioConfig.getDomain() + "/" + minioConfig.getBucketName() + "/"; + filePath = filePath.replace(publicPath3, ""); + + if (oldPath.equals(filePath)) { + // 处理方式2 + String publicPath4 = minioConfig.getUrl() + "/" + minioConfig.getBucketName() + "/"; + filePath = filePath.replace(publicPath4, ""); + } + return filePath; + } }