Browse Source

feat:【INFRA】文件存储,增加 enablePathStyleAccess 选项

YunaiV 1 year ago
parent
commit
46676a439d

+ 1 - 3
yudao-dependencies/pom.xml

@@ -96,10 +96,8 @@
             </dependency>
             <dependency>
                 <groupId>software.amazon.awssdk</groupId>
-                <artifactId>bom</artifactId>
+                <artifactId>s3</artifactId>
                 <version>${awssdk.version}</version>
-                <type>pom</type>
-                <scope>import</scope>
             </dependency>
 
             <!-- 业务组件 -->

+ 0 - 8
yudao-module-infra/yudao-module-infra-biz/pom.xml

@@ -120,14 +120,6 @@
             <groupId>software.amazon.awssdk</groupId>
             <artifactId>s3</artifactId>
         </dependency>
-        <dependency>
-            <groupId>software.amazon.awssdk</groupId>
-            <artifactId>auth</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>software.amazon.awssdk</groupId>
-            <artifactId>regions</artifactId>
-        </dependency>
 
         <dependency>
             <groupId>org.apache.tika</groupId>

+ 27 - 38
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java

@@ -5,10 +5,12 @@ import cn.hutool.core.util.StrUtil;
 import cn.hutool.http.HttpUtil;
 import cn.iocoder.yudao.module.infra.framework.file.core.client.AbstractFileClient;
 import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
+import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
 import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
 import software.amazon.awssdk.core.sync.RequestBody;
 import software.amazon.awssdk.regions.Region;
 import software.amazon.awssdk.services.s3.S3Client;
+import software.amazon.awssdk.services.s3.S3Configuration;
 import software.amazon.awssdk.services.s3.model.DeleteObjectRequest;
 import software.amazon.awssdk.services.s3.model.GetObjectRequest;
 import software.amazon.awssdk.services.s3.model.PutObjectRequest;
@@ -26,6 +28,7 @@ import java.time.Duration;
 public class S3FileClient extends AbstractFileClient<S3FileClientConfig> {
 
     private S3Client client;
+    private S3Presigner presigner;
 
     public S3FileClient(Long id, S3FileClientConfig config) {
         super(id, config);
@@ -38,11 +41,23 @@ public class S3FileClient extends AbstractFileClient<S3FileClientConfig> {
             config.setDomain(buildDomain());
         }
         // 初始化 S3 客户端
+        Region region = Region.of("us-east-1"); // 必须填,但填什么都行,常见的值有 "us-east-1",不填会报错
+        AwsCredentialsProvider credentialsProvider = StaticCredentialsProvider.create(
+                AwsBasicCredentials.create(config.getAccessKey(), config.getAccessSecret()));
+        URI endpoint = URI.create(buildEndpoint());
+        S3Configuration serviceConfiguration = S3Configuration.builder() // Path-style 访问
+                .pathStyleAccessEnabled(Boolean.TRUE.equals(config.getEnablePathStyleAccess())).build();
         client = S3Client.builder()
-                .credentialsProvider(buildCredentials())
-                .region(Region.of("us-east-1")) // 必须填,但填什么都行,常见的值有 "us-east-1",不填会报错
-                .endpointOverride(URI.create(buildEndpoint()))
-                //.serviceConfiguration(S3Configuration.builder().pathStyleAccessEnabled(true).build()) //  Path-style 访问
+                .credentialsProvider(credentialsProvider)
+                .region(region)
+                .endpointOverride(endpoint)
+                .serviceConfiguration(serviceConfiguration)
+                .build();
+        presigner = S3Presigner.builder()
+                .credentialsProvider(credentialsProvider)
+                .region(region)
+                .endpointOverride(endpoint)
+                .serviceConfiguration(serviceConfiguration)
                 .build();
     }
 
@@ -55,7 +70,6 @@ public class S3FileClient extends AbstractFileClient<S3FileClientConfig> {
                 .contentType(type)
                 .contentLength((long) content.length)
                 .build();
-
         // 上传文件
         client.putObject(putRequest, RequestBody.fromBytes(content));
         // 拼接返回路径
@@ -77,42 +91,27 @@ public class S3FileClient extends AbstractFileClient<S3FileClientConfig> {
                 .bucket(config.getBucket())
                 .key(path)
                 .build();
-
         return IoUtil.readBytes(client.getObject(getRequest));
     }
 
     @Override
     public FilePresignedUrlRespDTO getPresignedObjectUrl(String path) {
-        return new FilePresignedUrlRespDTO(getPresignedUrl(path, Duration.ofMinutes(10)), config.getDomain() + "/" + path);
-    }
-
-    /**
-     * 动态创建 S3Presigner
-     *
-     * @return S3Presigner
-     */
-    private S3Presigner createPresigner() {
-        return S3Presigner.builder()
-                .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create(config.getAccessKey(), config.getAccessSecret())))
-                .region(Region.of("us-east-1")) // 必须填,但填什么都行,常见的值有 "us-east-1",不填会报错
-                .endpointOverride(URI.create(buildEndpoint()))
-                .build();
+        Duration expiration = Duration.ofHours(24);
+        return new FilePresignedUrlRespDTO(getPresignedUrl(path, expiration), config.getDomain() + "/" + path);
     }
 
     /**
      * 生成动态的预签名上传 URL
      *
      * @param path     相对路径
-     * @param duration 过期时间
+     * @param expiration 过期时间
      * @return 生成的上传 URL
      */
-    public String getPresignedUrl(String path, Duration duration) {
-        try (S3Presigner presigner = createPresigner()) {
-            return presigner.presignPutObject(PutObjectPresignRequest.builder()
-                    .signatureDuration(duration)
-                    .putObjectRequest(b -> b.bucket(config.getBucket()).key(path))
-                    .build()).url().toString();
-        }
+    private String getPresignedUrl(String path, Duration expiration) {
+        return presigner.presignPutObject(PutObjectPresignRequest.builder()
+                .signatureDuration(expiration)
+                .putObjectRequest(b -> b.bucket(config.getBucket()).key(path))
+                .build()).url().toString();
     }
 
     /**
@@ -129,16 +128,6 @@ public class S3FileClient extends AbstractFileClient<S3FileClientConfig> {
         return StrUtil.format("https://{}.{}", config.getBucket(), config.getEndpoint());
     }
 
-    /**
-     * 基于 config 秘钥,构建 S3 客户端的认证信息
-     *
-     * @return S3 客户端的认证信息
-     */
-    private StaticCredentialsProvider buildCredentials() {
-        return StaticCredentialsProvider.create(
-                AwsBasicCredentials.create(config.getAccessKey(), config.getAccessSecret()));
-    }
-
     /**
      * 节点地址补全协议头
      *

+ 6 - 0
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClientConfig.java

@@ -67,6 +67,12 @@ public class S3FileClientConfig implements FileClientConfig {
     @NotNull(message = "accessSecret 不能为空")
     private String accessSecret;
 
+    /**
+     * 是否启用 PathStyle 访问
+     */
+    @NotNull(message = "enablePathStyleAccess 不能为空")
+    private Boolean enablePathStyleAccess;
+
     @SuppressWarnings("RedundantIfStatement")
     @AssertTrue(message = "domain 不能为空")
     @JsonIgnore