From 30558aa7e1d16da2d7f6d8d03df5226a1d46b166 Mon Sep 17 00:00:00 2001 From: duandazhi Date: Mon, 19 Jul 2021 19:53:32 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=AD=BE=E5=90=8D=E7=9A=84ur?= =?UTF-8?q?l[presignedUrl],=20minio=E5=92=8Caliyun=20oss=E5=BC=80=E5=8F=91?= =?UTF-8?q?=E3=80=81=E6=B5=8B=E8=AF=95=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ruoyi/file/config/MinioConfig.java | 4 +- .../file/controller/SysFileController.java | 20 ++++- .../file/service/AliyunOssDsfServiceImpl.java | 9 ++- .../file/service/CephDfsServiceImpl.java | 5 ++ .../file/service/FastDfsServiceImpl.java | 5 ++ .../file/service/FtpFileServiceImpl.java | 5 ++ .../com/ruoyi/file/service/IDfsService.java | 16 ++++ .../file/service/LocalFileServiceImpl.java | 5 ++ .../file/service/MinioDfsServiceImpl.java | 79 ++++++++++++++++--- .../file/service/QiniuDfsServiceImpl.java | 7 ++ .../src/main/resources/bootstrap.yml | 4 +- 11 files changed, 144 insertions(+), 15 deletions(-) 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 c0e89be3..7efa2b85 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 @@ -21,7 +21,7 @@ import org.springframework.stereotype.Component; public class MinioConfig { public static final String PREFIX = "minio"; /** - * 服务地址 + * 服务地址url 或者叫做 endpoint * eg: http://192.168.254.100:9900 */ private String url; @@ -46,7 +46,7 @@ public class MinioConfig { /** * 访问域名; url经常是内网地址,外部访问用域名或者外网ip - * eg: https://image.bj.gov.cn/appt-file + * eg: https://yq666.bj.gov.cn/appt-file */ private String domain; 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 4952f628..7f8d25ae 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,12 +1,15 @@ package com.ruoyi.file.controller; import com.ruoyi.file.service.IDfsService; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import org.apache.commons.lang3.StringUtils; 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; @@ -46,6 +49,7 @@ public class SysFileController { /** * 删除文件 */ + @ApiOperation(value = "删除文件", notes = "根据文件的完整url进行删除资源") @PostMapping("delete") public R delete(String fileUrl) { if (StringUtils.isBlank(fileUrl)) { @@ -65,8 +69,22 @@ public class SysFileController { * 获取文件总大小,占用内容大小; * 形如:总 233.57 GB, 可用 72.12 GB */ + @ApiOperation(value = "获取文件服务器的容量", notes = "获取文件服务器占用资源的容量,剩余容量(可选)") @GetMapping("objectsCapacityStr") - public R objectsCapacityStr() { + public R capacityStr() { return R.ok(dfsService.objectsCapacityStr(), "获取成功"); } + + /** + * 对访问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 + */ + @ApiOperation(value = "临时安全凭证、获取加签的url", notes = "根据输入的url,获取带有临时安全凭证的url") + @GetMapping("getPresignedUrl") + public R getPresignedUrl( + @ApiParam("需要访问的url,字段名:fileUrl,必填;不要带有?后面的参数") @RequestParam(value = "fileUrl") String fileUrl) { + return R.ok(dfsService.presignedUrl(fileUrl), "获取成功"); + } } \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/AliyunOssDsfServiceImpl.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/AliyunOssDsfServiceImpl.java index b9429499..3299de61 100644 --- a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/AliyunOssDsfServiceImpl.java +++ b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/AliyunOssDsfServiceImpl.java @@ -42,6 +42,7 @@ import java.util.concurrent.TimeUnit; * @date 2019/8/6 19:02 * //@see AliyunMsgUtil */ +//@Primary @Service public class AliyunOssDsfServiceImpl implements IDfsService { private static final Logger log = LoggerFactory.getLogger(AliyunOssDsfServiceImpl.class); @@ -516,6 +517,12 @@ public class AliyunOssDsfServiceImpl implements IDfsService { return result; } + @Override + public String presignedUrl(String fileUrl) { + String objectKey = this.getStorePath(fileUrl); + return this.getStsURL(objectKey); + } + /** * 阿里云 对象存储 oss 使用签名URL进行临时授权 * https://help.aliyun.com/document_detail/32016.html?spm=a2c4g.11186623.6.992.7a943b4aPjkyTA#title-pu8-5o8-x7j @@ -523,7 +530,7 @@ public class AliyunOssDsfServiceImpl implements IDfsService { * @param objectName 完成的url, filePath * @return 返回url签名之后的url */ - public String getStsURL(String objectName) { + private String getStsURL(String objectName) { if (StringUtils.isBlank(objectName)) { return objectName; } diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/CephDfsServiceImpl.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/CephDfsServiceImpl.java index ff410e88..bdfa1b05 100644 --- a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/CephDfsServiceImpl.java +++ b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/CephDfsServiceImpl.java @@ -129,6 +129,11 @@ public class CephDfsServiceImpl implements IDfsService { throw new CustomException("ceph-获取文件占用空间功能,敬请期待"); } + @Override + public String presignedUrl(String fileUrl) { + return fileUrl; + } + /** * 转换url * diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/FastDfsServiceImpl.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/FastDfsServiceImpl.java index 7f7af301..e7ddacef 100644 --- a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/FastDfsServiceImpl.java +++ b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/FastDfsServiceImpl.java @@ -72,4 +72,9 @@ public class FastDfsServiceImpl implements IDfsService public String objectsCapacityStr() { throw new CustomException("fastdfs-获取文件占用空间功能,敬请期待"); } + + @Override + public String presignedUrl(String fileUrl) { + return fileUrl; + } } diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/FtpFileServiceImpl.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/FtpFileServiceImpl.java index 14f7c077..df0a9de7 100644 --- a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/FtpFileServiceImpl.java +++ b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/FtpFileServiceImpl.java @@ -77,6 +77,11 @@ public class FtpFileServiceImpl implements IDfsService { throw new CustomException("fpt-获取文件占用空间功能,敬请期待"); } + @Override + public String presignedUrl(String fileUrl) { + return fileUrl; + } + /** * 转换url,为原始的key * diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/IDfsService.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/IDfsService.java index 4440fbf8..8075da0e 100644 --- a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/IDfsService.java +++ b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/IDfsService.java @@ -65,6 +65,22 @@ public interface IDfsService */ String objectsCapacityStr(); + /** + * 对访问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 ;七牛云存储; 构建时间戳防盗链访问链接: https://developer.qiniu.com/kodo/1239/java#fusion-antileech + * https://developer.qiniu.com/kodo/5914/s3-compatible-sts + * 4、腾讯 临时密钥(临时访问凭证) GetFederationToken 临时密钥生成及使用指引 https://cloud.tencent.com/document/product/436/14048?from=10680 + * @param fileUrl 文件访问地址,全路径或者不是全路径都可以 + * @return 返回签名后的url + */ + String presignedUrl(String fileUrl); + /** * 校验文件名称长度 & 校验文件大小 & 校验上传的目录是否是项目中注册了的 & 返回新的文件名称 * diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/LocalFileServiceImpl.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/LocalFileServiceImpl.java index 505539c9..6a6f5c20 100644 --- a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/LocalFileServiceImpl.java +++ b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/LocalFileServiceImpl.java @@ -84,6 +84,11 @@ public class LocalFileServiceImpl implements IDfsService return "总 " + totalSpace + ", 可用 " + freeSpace; } + @Override + public String presignedUrl(String fileUrl) { + return fileUrl; + } + /** * 转换url,为原始的key * diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/MinioDfsServiceImpl.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/MinioDfsServiceImpl.java index 4f8b742f..57fcc984 100644 --- a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/MinioDfsServiceImpl.java +++ b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/MinioDfsServiceImpl.java @@ -1,21 +1,24 @@ package com.ruoyi.file.service; import cn.hutool.extra.spring.SpringUtil; -import com.ruoyi.common.core.exception.CustomException; -import io.minio.RemoveObjectArgs; +import io.minio.*; import io.minio.errors.*; +import io.minio.http.Method; +import io.minio.messages.Item; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import com.ruoyi.file.config.MinioConfig; -import io.minio.MinioClient; -import io.minio.PutObjectArgs; import java.io.IOException; +import java.math.BigDecimal; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Consumer; /** * Minio 文件存储 @@ -38,7 +41,7 @@ public class MinioDfsServiceImpl implements IDfsService @Autowired private MinioConfig minioConfig; @Autowired - private MinioClient client; + private MinioClient minioClient; /** * 本地文件上传接口 @@ -68,9 +71,9 @@ public class MinioDfsServiceImpl implements IDfsService .stream(file.getInputStream(), file.getSize(), -1) .contentType(file.getContentType()) .build(); - client.putObject(args); + minioClient.putObject(args); //return minioConfig.getUrl() + "/" + minioConfig.getBucketName() + "/" + fileName; - //形如:https://image.bj.gov.cn/appt-file/dev/default/2021/07/18/f4243eb2-06a1-4304-bdfc-e2964b8721bb.jpeg + //形如:https://yq666.bj.gov.cn/appt-file/dev/default/2021/07/18/f4243eb2-06a1-4304-bdfc-e2964b8721bb.jpeg return minioConfig.getDomain() + "/" + minioConfig.getBucketName() + "/" + fileName; } @@ -81,7 +84,7 @@ public class MinioDfsServiceImpl implements IDfsService object(getStorePath(fileUrl)). build(); try { - client.removeObject(args); + minioClient.removeObject(args); return true; } catch (ErrorResponseException | InsufficientDataException | @@ -99,13 +102,69 @@ public class MinioDfsServiceImpl implements IDfsService @Override public String objectsCapacityStr() { - throw new CustomException("minio存储-获取文件占用空间功能,敬请期待"); + /*MinioClient minioClient = MinioClient.builder().endpoint(minioConfig.getUrl()) + .credentials(minioConfig.getAccessKey(), minioConfig.getSecretKey()) + .build();*/ + + AtomicLong atomicLong = new AtomicLong(); + atomicLong.set(0); + String result = ""; + + ListObjectsArgs args = ListObjectsArgs.builder().bucket(minioConfig.getBucketName()).build(); + minioClient.listObjects(args).forEach(new Consumer>() { + @Override + public void accept(Result itemResult) { + try { + atomicLong.addAndGet(itemResult.get().size() / 1024); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + + long size = atomicLong.get(); + if (size > (1024 * 1024)) { + result = (new BigDecimal((double) size / 1024 / 1024)).setScale(2, BigDecimal.ROUND_HALF_UP) + "GB"; + } else if (size > 1024) { + result = (new BigDecimal((double) size / 1024).setScale(2, BigDecimal.ROUND_HALF_UP)) + "MB"; + } else { + result = size + "KB"; + } + + return result; + } + + /** + * 给原始的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 预签】 + */ + @Override + public String presignedUrl(String fileUrl) { + String objectName = this.getStorePath(fileUrl); + GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder(). + bucket(minioConfig.getBucketName()). + method(Method.GET). + object(objectName).expiry(5, TimeUnit.DAYS).build(); + + String presignedObjectUrl = null; + try { + presignedObjectUrl = minioClient.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://image.bj.gov.cn/appt-file/dev/default/2021/07/18/f4243eb2-06a1-4304-bdfc-e2964b8721bb.jpeg + * @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) { diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/QiniuDfsServiceImpl.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/QiniuDfsServiceImpl.java index 3961fa7f..24cfdebc 100644 --- a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/QiniuDfsServiceImpl.java +++ b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/QiniuDfsServiceImpl.java @@ -29,6 +29,8 @@ import java.io.InputStream; * @see QiniuKodoConfig * 参考:https://developer.qiniu.com/kodo/1239/java#upload-stream * 路径:【对象存储==>JAVASDK==>文件上传==>数据流上传】 + * + * 构建时间戳防盗链访问链接: https://developer.qiniu.com/kodo/1239/java#fusion-antileech */ //@Primary @Service @@ -116,6 +118,11 @@ public class QiniuDfsServiceImpl implements IDfsService { throw new CustomException("七牛云-获取文件占用空间功能,敬请期待"); } + @Override + public String presignedUrl(String fileUrl) { + return fileUrl; + } + /** * 转换url,为原始的key * diff --git a/ruoyi-modules/ruoyi-file/src/main/resources/bootstrap.yml b/ruoyi-modules/ruoyi-file/src/main/resources/bootstrap.yml index 759ed476..4b439b6e 100644 --- a/ruoyi-modules/ruoyi-file/src/main/resources/bootstrap.yml +++ b/ruoyi-modules/ruoyi-file/src/main/resources/bootstrap.yml @@ -17,9 +17,11 @@ spring: discovery: # 服务注册地址 server-addr: 127.0.0.1:8848 + namespace: 72b686a1-d9f6-499f-8275-e481b664779e config: # 配置中心地址 server-addr: 127.0.0.1:8848 + namespace: 72b686a1-d9f6-499f-8275-e481b664779e # 配置文件格式 file-extension: yml # 共享配置 @@ -54,7 +56,7 @@ minio: accessKey: D99KGE6ZTQXSATTJWU24 secretKey: QyVqGnhIQQE734UYSUFlGOZViE6+ZlDEfUG3NjhJ bucketName: appt-file - domain: https://image.bj.gov.cn + domain: https://yq666.bj.gov.cn # 文件服务器之5 aliyun oss aliyun-oss: