From c56ca7879332050cc8ffca56d6adadb61dba3e6d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=8B=A5=E5=88=9D995?= <2308850421@qq.com>
Date: Sun, 3 Sep 2023 01:14:21 +0000
Subject: [PATCH 1/2] =?UTF-8?q?:sparkles:=20=E6=94=AF=E6=8C=81S3=E5=AD=98?=
=?UTF-8?q?=E5=82=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../common/storage/impl/MinIoStorage.java | 8 +-
.../common/storage/impl/S3Storage.java | 192 ++++++++++++++++++
.../setting/StorageSettingConverter.java | 2 +-
3 files changed, 197 insertions(+), 5 deletions(-)
create mode 100644 eiam-common/src/main/java/cn/topiam/employee/common/storage/impl/S3Storage.java
diff --git a/eiam-common/src/main/java/cn/topiam/employee/common/storage/impl/MinIoStorage.java b/eiam-common/src/main/java/cn/topiam/employee/common/storage/impl/MinIoStorage.java
index 584177f6..5e637eec 100644
--- a/eiam-common/src/main/java/cn/topiam/employee/common/storage/impl/MinIoStorage.java
+++ b/eiam-common/src/main/java/cn/topiam/employee/common/storage/impl/MinIoStorage.java
@@ -67,8 +67,8 @@ public class MinIoStorage extends AbstractStorage {
.credentials(minioConfig.getAccessKey(), minioConfig.getSecretKey()).build();
createBucket(this.minioClient, minioConfig);
} catch (Exception e) {
- log.error("Create bucket excception: {}", e.getMessage(), e);
- throw new StorageProviderException("Create bucket excception", e);
+ log.error("Create bucket exception: {}", e.getMessage(), e);
+ throw new StorageProviderException("Create bucket exception", e);
}
}
@@ -100,7 +100,7 @@ public class MinIoStorage extends AbstractStorage {
+ SEPARATOR
+ URLEncoder.encode(key, StandardCharsets.UTF_8).replaceAll("\\+", "%20");
} catch (Exception e) {
- log.error("minio download exception: {}", e.getMessage(), e);
+ log.error("minio upload exception: {}", e.getMessage(), e);
throw new StorageProviderException("minio upload exception", e);
}
}
@@ -117,7 +117,7 @@ public class MinIoStorage extends AbstractStorage {
return downloadUrl.replace(minioConfig.getEndpoint(), minioConfig.getDomain());
} catch (Exception e) {
log.error("minio download exception: {}", e.getMessage(), e);
- throw new StorageProviderException("minio upload exception", e);
+ throw new StorageProviderException("minio download exception", e);
}
}
diff --git a/eiam-common/src/main/java/cn/topiam/employee/common/storage/impl/S3Storage.java b/eiam-common/src/main/java/cn/topiam/employee/common/storage/impl/S3Storage.java
new file mode 100644
index 00000000..45c04722
--- /dev/null
+++ b/eiam-common/src/main/java/cn/topiam/employee/common/storage/impl/S3Storage.java
@@ -0,0 +1,192 @@
+/*
+ * eiam-common - Employee Identity and Access Management
+ * Copyright © 2022-Present Jinan Yuanchuang Network Technology Co., Ltd. (support@topiam.cn)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package cn.topiam.employee.common.storage.impl;
+
+import cn.topiam.employee.common.storage.AbstractStorage;
+import cn.topiam.employee.common.storage.StorageConfig;
+import cn.topiam.employee.common.storage.StorageProviderException;
+import lombok.extern.slf4j.Slf4j;
+import org.jetbrains.annotations.NotNull;
+import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
+import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
+import software.amazon.awssdk.core.sync.RequestBody;
+import software.amazon.awssdk.core.waiters.WaiterResponse;
+import software.amazon.awssdk.regions.Region;
+import software.amazon.awssdk.services.s3.S3Client;
+import software.amazon.awssdk.services.s3.model.*;
+import software.amazon.awssdk.services.s3.waiters.S3Waiter;
+
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * S3 协议实现
+ *
+ * @author TopIAM
+ * Created by support@topiam.cn on 2023/08/29 22:30
+ */
+@Slf4j
+public class S3Storage extends AbstractStorage {
+
+ private final S3Client s3Client;
+
+ private final StorageConfig.Config config;
+
+ public S3Storage(StorageConfig config) {
+ super(config);
+ // 创建连接
+
+ // 凭证
+ AwsBasicCredentials creds;
+ this.config = config.getConfig();
+ try {
+ // 阿里云
+ if (this.config instanceof AliYunOssStorage.Config) {
+ String accessKeyId = ((AliYunOssStorage.Config) this.config).getAccessKeyId();
+ String accessKeySecret = ((AliYunOssStorage.Config) this.config)
+ .getAccessKeySecret();
+ String endpoint = ((AliYunOssStorage.Config) this.config).getEndpoint();
+ creds = AwsBasicCredentials.create(accessKeyId, accessKeySecret);
+ this.s3Client = S3Client.builder()
+ .serviceConfiguration(b -> b.checksumValidationEnabled(false))
+ .credentialsProvider(StaticCredentialsProvider.create(creds))
+ .endpointOverride(new URI(endpoint)).build();
+ }
+ // MiniO
+ else if (this.config instanceof MinIoStorage.Config) {
+ String accessKey = ((MinIoStorage.Config) this.config).getAccessKey();
+ String secretKey = ((MinIoStorage.Config) this.config).getSecretKey();
+ String endpoint = ((MinIoStorage.Config) this.config).getEndpoint();
+ creds = AwsBasicCredentials.create(accessKey, secretKey);
+ this.s3Client = S3Client.builder()
+ .serviceConfiguration(b -> b.checksumValidationEnabled(false))
+ .credentialsProvider(StaticCredentialsProvider.create(creds))
+ .endpointOverride(new URI(endpoint)).build();
+ }
+ // 七牛云
+ else if (this.config instanceof QiNiuKodoStorage.Config) {
+ String accessKey = ((QiNiuKodoStorage.Config) this.config).getAccessKey();
+ String secretKey = ((QiNiuKodoStorage.Config) this.config).getSecretKey();
+ String domain = this.config.getDomain();
+ creds = AwsBasicCredentials.create(accessKey, secretKey);
+ this.s3Client = S3Client.builder()
+ .serviceConfiguration(b -> b.checksumValidationEnabled(false))
+ .credentialsProvider(StaticCredentialsProvider.create(creds))
+ .endpointOverride(new URI(domain)).build();
+ }
+ // 腾讯云
+ else if (this.config instanceof TencentCosStorage.Config) {
+ String secretId = ((TencentCosStorage.Config) this.config).getSecretId();
+ String secretKey = ((TencentCosStorage.Config) this.config).getSecretKey();
+ String domain = this.config.getDomain();
+ String region = ((TencentCosStorage.Config) this.config).getRegion();
+ creds = AwsBasicCredentials.create(secretId, secretKey);
+ this.s3Client = S3Client.builder()
+ .serviceConfiguration(b -> b.checksumValidationEnabled(false))
+ .credentialsProvider(StaticCredentialsProvider.create(creds))
+ .region(Region.of(region)).endpointOverride(new URI(domain)).build();
+ }
+ // 错误
+ else {
+ throw new StorageProviderException("s3Client initialize exception");
+ }
+ createBucket(getBucket());
+ } catch (Exception e) {
+ log.error("s3Client initialize exception: {}", e.getMessage(), e);
+ throw new StorageProviderException("s3Client initialize exception", e);
+ }
+ }
+
+ private void createBucket(String bucket) throws Exception {
+ try {
+ // 创建bucket
+ S3Waiter s3Waiter = this.s3Client.waiter();
+ CreateBucketRequest bucketRequest = CreateBucketRequest.builder().bucket(bucket).build();
+ // 获取bucket是否存在
+ this.s3Client.createBucket(bucketRequest);
+ HeadBucketRequest bucketRequestWait = HeadBucketRequest.builder().bucket(bucket).build();
+ WaiterResponse waiterResponse = s3Waiter
+ .waitUntilBucketExists(bucketRequestWait);
+ waiterResponse.matched().response().ifPresent(System.out::println);
+ } catch (Exception e) {
+ log.error("create bucket exception: {}", e.getMessage(), e);
+ throw new StorageProviderException("create bucket exception", e);
+ }
+ }
+
+ @Override
+ public String upload(@NotNull String fileName,
+ InputStream inputStream) throws StorageProviderException {
+ try {
+ super.upload(fileName, inputStream);
+ String bucket = getBucket();
+ String key = this.config.getLocation() + SEPARATOR + getFileName(fileName);
+ // 写object
+ PutObjectRequest putOb = PutObjectRequest.builder().bucket(bucket).key(key).build();
+ this.s3Client.putObject(putOb,
+ RequestBody.fromInputStream(inputStream, inputStream.readAllBytes().length));
+ return this.config.getDomain() + SEPARATOR + bucket + SEPARATOR
+ + URLEncoder.encode(key, StandardCharsets.UTF_8).replaceAll("\\+", "%20");
+ } catch (Exception e) {
+ log.error("s3Client upload exception: {}", e.getMessage(), e);
+ throw new StorageProviderException("s3Client upload exception", e);
+ }
+ }
+
+ @Override
+ public String download(String path) throws StorageProviderException {
+ try {
+ super.download(path);
+ String bucket = getBucket();
+ GetUrlRequest request = GetUrlRequest.builder().bucket(bucket).key(path).build();
+
+ URL url = this.s3Client.utilities().getUrl(request);
+ return url.toString();
+ } catch (Exception e) {
+ log.error("s3Client download exception: {}", e.getMessage(), e);
+ throw new StorageProviderException("s3Client download exception", e);
+ }
+ }
+
+ private String getBucket() {
+ String bucket = "";
+ if (this.config instanceof AliYunOssStorage.Config) {
+ bucket = ((AliYunOssStorage.Config) this.config).getBucket();
+ }
+ // MiniO
+ else if (this.config instanceof MinIoStorage.Config) {
+ bucket = ((MinIoStorage.Config) this.config).getBucket();
+ }
+ // 七牛云
+ else if (this.config instanceof QiNiuKodoStorage.Config) {
+ bucket = ((QiNiuKodoStorage.Config) this.config).getBucket();
+ }
+ // 腾讯云
+ else if (this.config instanceof TencentCosStorage.Config) {
+ bucket = ((TencentCosStorage.Config) this.config).getBucket();
+ }
+ // 错误
+ else {
+ throw new StorageProviderException("getBucket exception");
+ }
+ return bucket;
+ }
+}
diff --git a/eiam-console/src/main/java/cn/topiam/employee/console/converter/setting/StorageSettingConverter.java b/eiam-console/src/main/java/cn/topiam/employee/console/converter/setting/StorageSettingConverter.java
index edd6c36a..f934ed0a 100644
--- a/eiam-console/src/main/java/cn/topiam/employee/console/converter/setting/StorageSettingConverter.java
+++ b/eiam-console/src/main/java/cn/topiam/employee/console/converter/setting/StorageSettingConverter.java
@@ -45,7 +45,7 @@ import jakarta.validation.ValidationException;
import static cn.topiam.employee.core.setting.constant.StorageProviderSettingConstants.STORAGE_PROVIDER_KEY;
/**
- * 消息设置转换器
+ * 对象存储设置转换器
*
* @author TopIAM
* Created by support@topiam.cn on 2021/10/1 23:18
From 264febf4b3fec253a62429abe3f70baea0b42948 Mon Sep 17 00:00:00 2001
From: kay <729048330@qq.com>
Date: Mon, 4 Sep 2023 13:19:57 +0000
Subject: [PATCH 2/2] =?UTF-8?q?=E5=AD=98=E5=82=A8=E9=85=8D=E7=BD=AE?=
=?UTF-8?q?=E6=94=AF=E6=8C=81S3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../common/storage/enums/StorageProvider.java | 6 +-
.../common/storage/impl/S3Storage.java | 239 +++++++++---------
.../pages/setting/Storage/StorageProvider.tsx | 8 +
.../setting/Storage/components/S3/index.tsx | 120 +++++++++
.../src/pages/setting/Storage/constant.ts | 1 +
.../pages/setting/Storage/locales/zh-CN.ts | 25 ++
.../setting/StorageSettingConverter.java | 20 +-
.../controller/AppAccountController.java | 105 ++++++++
.../portal/converter/AppAccountConverter.java | 51 ++++
.../pojo/request/AppAccountRequest.java | 55 ++++
.../portal/service/AppAccountService.java | 53 ++++
.../service/impl/AppAccountServiceImpl.java | 134 ++++++++++
12 files changed, 692 insertions(+), 125 deletions(-)
create mode 100644 eiam-console/src/main/console-fe/src/pages/setting/Storage/components/S3/index.tsx
create mode 100644 eiam-portal/src/main/java/cn/topiam/employee/portal/controller/AppAccountController.java
create mode 100644 eiam-portal/src/main/java/cn/topiam/employee/portal/converter/AppAccountConverter.java
create mode 100644 eiam-portal/src/main/java/cn/topiam/employee/portal/pojo/request/AppAccountRequest.java
create mode 100644 eiam-portal/src/main/java/cn/topiam/employee/portal/service/AppAccountService.java
create mode 100644 eiam-portal/src/main/java/cn/topiam/employee/portal/service/impl/AppAccountServiceImpl.java
diff --git a/eiam-common/src/main/java/cn/topiam/employee/common/storage/enums/StorageProvider.java b/eiam-common/src/main/java/cn/topiam/employee/common/storage/enums/StorageProvider.java
index 9ea064fc..3d8ae95d 100644
--- a/eiam-common/src/main/java/cn/topiam/employee/common/storage/enums/StorageProvider.java
+++ b/eiam-common/src/main/java/cn/topiam/employee/common/storage/enums/StorageProvider.java
@@ -51,7 +51,11 @@ public enum StorageProvider implements Serializable {
/**
* minio
*/
- MINIO("minio", "minio", MinIoStorage.class);
+ MINIO("minio", "minio", MinIoStorage.class),
+ /**
+ * S3
+ */
+ S3("s3", "s3", S3Storage.class);
/**
* code
diff --git a/eiam-common/src/main/java/cn/topiam/employee/common/storage/impl/S3Storage.java b/eiam-common/src/main/java/cn/topiam/employee/common/storage/impl/S3Storage.java
index 45c04722..192d9445 100644
--- a/eiam-common/src/main/java/cn/topiam/employee/common/storage/impl/S3Storage.java
+++ b/eiam-common/src/main/java/cn/topiam/employee/common/storage/impl/S3Storage.java
@@ -17,25 +17,36 @@
*/
package cn.topiam.employee.common.storage.impl;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.time.Duration;
+
+import org.apache.commons.lang3.StringUtils;
+import org.hibernate.validator.constraints.URL;
+import org.jetbrains.annotations.NotNull;
+
+import cn.topiam.employee.common.jackjson.encrypt.JsonPropertyEncrypt;
import cn.topiam.employee.common.storage.AbstractStorage;
import cn.topiam.employee.common.storage.StorageConfig;
import cn.topiam.employee.common.storage.StorageProviderException;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
-import org.jetbrains.annotations.NotNull;
+
+import jakarta.validation.constraints.NotEmpty;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.core.sync.RequestBody;
-import software.amazon.awssdk.core.waiters.WaiterResponse;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.*;
-import software.amazon.awssdk.services.s3.waiters.S3Waiter;
-
-import java.io.InputStream;
-import java.net.URI;
-import java.net.URL;
-import java.net.URLEncoder;
-import java.nio.charset.StandardCharsets;
+import software.amazon.awssdk.services.s3.presigner.S3Presigner;
+import software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest;
+import software.amazon.awssdk.services.s3.presigner.model.PresignedGetObjectRequest;
+import static cn.topiam.employee.common.constant.StorageConstants.URL_REGEXP;
/**
* S3 协议实现
@@ -46,86 +57,55 @@ import java.nio.charset.StandardCharsets;
@Slf4j
public class S3Storage extends AbstractStorage {
- private final S3Client s3Client;
+ private final S3Client s3Client;
- private final StorageConfig.Config config;
+ private final S3Presigner s3Presigner;
+
+ private final Config s3Config;
public S3Storage(StorageConfig config) {
super(config);
- // 创建连接
-
- // 凭证
- AwsBasicCredentials creds;
- this.config = config.getConfig();
- try {
- // 阿里云
- if (this.config instanceof AliYunOssStorage.Config) {
- String accessKeyId = ((AliYunOssStorage.Config) this.config).getAccessKeyId();
- String accessKeySecret = ((AliYunOssStorage.Config) this.config)
- .getAccessKeySecret();
- String endpoint = ((AliYunOssStorage.Config) this.config).getEndpoint();
- creds = AwsBasicCredentials.create(accessKeyId, accessKeySecret);
- this.s3Client = S3Client.builder()
- .serviceConfiguration(b -> b.checksumValidationEnabled(false))
- .credentialsProvider(StaticCredentialsProvider.create(creds))
- .endpointOverride(new URI(endpoint)).build();
- }
- // MiniO
- else if (this.config instanceof MinIoStorage.Config) {
- String accessKey = ((MinIoStorage.Config) this.config).getAccessKey();
- String secretKey = ((MinIoStorage.Config) this.config).getSecretKey();
- String endpoint = ((MinIoStorage.Config) this.config).getEndpoint();
- creds = AwsBasicCredentials.create(accessKey, secretKey);
- this.s3Client = S3Client.builder()
- .serviceConfiguration(b -> b.checksumValidationEnabled(false))
- .credentialsProvider(StaticCredentialsProvider.create(creds))
- .endpointOverride(new URI(endpoint)).build();
- }
- // 七牛云
- else if (this.config instanceof QiNiuKodoStorage.Config) {
- String accessKey = ((QiNiuKodoStorage.Config) this.config).getAccessKey();
- String secretKey = ((QiNiuKodoStorage.Config) this.config).getSecretKey();
- String domain = this.config.getDomain();
- creds = AwsBasicCredentials.create(accessKey, secretKey);
- this.s3Client = S3Client.builder()
- .serviceConfiguration(b -> b.checksumValidationEnabled(false))
- .credentialsProvider(StaticCredentialsProvider.create(creds))
- .endpointOverride(new URI(domain)).build();
- }
- // 腾讯云
- else if (this.config instanceof TencentCosStorage.Config) {
- String secretId = ((TencentCosStorage.Config) this.config).getSecretId();
- String secretKey = ((TencentCosStorage.Config) this.config).getSecretKey();
- String domain = this.config.getDomain();
- String region = ((TencentCosStorage.Config) this.config).getRegion();
- creds = AwsBasicCredentials.create(secretId, secretKey);
- this.s3Client = S3Client.builder()
- .serviceConfiguration(b -> b.checksumValidationEnabled(false))
- .credentialsProvider(StaticCredentialsProvider.create(creds))
- .region(Region.of(region)).endpointOverride(new URI(domain)).build();
- }
- // 错误
- else {
- throw new StorageProviderException("s3Client initialize exception");
- }
- createBucket(getBucket());
- } catch (Exception e) {
- log.error("s3Client initialize exception: {}", e.getMessage(), e);
- throw new StorageProviderException("s3Client initialize exception", e);
- }
+ // 获取客户端
+ this.s3Config = (Config) this.config.getConfig();
+ this.s3Client = getS3Client();
+ this.s3Presigner = getS3Presigner();
+ createBucket();
}
- private void createBucket(String bucket) throws Exception {
+ private S3Client getS3Client() {
+ return S3Client.builder().serviceConfiguration(b -> b.checksumValidationEnabled(false))
+ .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials
+ .create(s3Config.getAccessKeyId(), s3Config.getSecretAccessKey())))
+ .region(getRegion()).endpointOverride(URI.create(s3Config.getEndpoint())).build();
+ }
+
+ private S3Presigner getS3Presigner() {
+ return S3Presigner.builder().region(getRegion())
+ .endpointOverride(URI.create(s3Config.getEndpoint()))
+ .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials
+ .create(s3Config.getAccessKeyId(), s3Config.getSecretAccessKey())))
+ .build();
+ }
+
+ /**
+ * 创建Bucket
+ */
+ protected void createBucket() {
try {
- // 创建bucket
- S3Waiter s3Waiter = this.s3Client.waiter();
- CreateBucketRequest bucketRequest = CreateBucketRequest.builder().bucket(bucket).build();
// 获取bucket是否存在
- this.s3Client.createBucket(bucketRequest);
- HeadBucketRequest bucketRequestWait = HeadBucketRequest.builder().bucket(bucket).build();
- WaiterResponse waiterResponse = s3Waiter
- .waitUntilBucketExists(bucketRequestWait);
- waiterResponse.matched().response().ifPresent(System.out::println);
+ HeadBucketRequest bucketRequestWait = HeadBucketRequest.builder()
+ .bucket(this.s3Config.getBucket()).build();
+ s3Client.headBucket(bucketRequestWait);
+ } catch (S3Exception se) {
+ if (se.statusCode() == 404) {
+ // 创建bucket
+ CreateBucketRequest bucketRequest = CreateBucketRequest.builder()
+ .bucket(this.s3Config.getBucket()).build();
+ this.s3Client.createBucket(bucketRequest);
+ } else {
+ log.error("查询bucket是否存在异常:[{}]", se.getMessage(), se);
+ throw se;
+ }
} catch (Exception e) {
log.error("create bucket exception: {}", e.getMessage(), e);
throw new StorageProviderException("create bucket exception", e);
@@ -136,57 +116,76 @@ public class S3Storage extends AbstractStorage {
public String upload(@NotNull String fileName,
InputStream inputStream) throws StorageProviderException {
try {
- super.upload(fileName, inputStream);
- String bucket = getBucket();
- String key = this.config.getLocation() + SEPARATOR + getFileName(fileName);
- // 写object
- PutObjectRequest putOb = PutObjectRequest.builder().bucket(bucket).key(key).build();
- this.s3Client.putObject(putOb,
- RequestBody.fromInputStream(inputStream, inputStream.readAllBytes().length));
- return this.config.getDomain() + SEPARATOR + bucket + SEPARATOR
+ String key = s3Config.getLocation() + SEPARATOR + getFileName(fileName);
+ PutObjectRequest putOb = PutObjectRequest.builder().bucket(s3Config.getBucket())
+ .key(key).build();
+ this.s3Client.putObject(putOb, RequestBody.fromBytes(inputStream.readAllBytes()));
+ return this.s3Config.getDomain() + SEPARATOR
+ URLEncoder.encode(key, StandardCharsets.UTF_8).replaceAll("\\+", "%20");
} catch (Exception e) {
- log.error("s3Client upload exception: {}", e.getMessage(), e);
- throw new StorageProviderException("s3Client upload exception", e);
+ log.error("[{}] upload exception: {}", this.config.getProvider(), e.getMessage(), e);
+ throw new StorageProviderException("upload exception", e);
}
}
@Override
public String download(String path) throws StorageProviderException {
try {
- super.download(path);
- String bucket = getBucket();
- GetUrlRequest request = GetUrlRequest.builder().bucket(bucket).key(path).build();
-
- URL url = this.s3Client.utilities().getUrl(request);
- return url.toString();
+ GetObjectRequest getObjectRequest = GetObjectRequest.builder()
+ .bucket(this.s3Config.getBucket()).key(path).build();
+ GetObjectPresignRequest getObjectPresignRequest = GetObjectPresignRequest.builder()
+ .signatureDuration(Duration.ofSeconds(EXPIRY_SECONDS))
+ .getObjectRequest(getObjectRequest).build();
+ PresignedGetObjectRequest presignedGetObjectRequest = s3Presigner
+ .presignGetObject(getObjectPresignRequest);
+ String downloadUrl = presignedGetObjectRequest.url().toString();
+ return downloadUrl.replace(this.s3Config.getEndpoint(), this.s3Config.getDomain());
} catch (Exception e) {
- log.error("s3Client download exception: {}", e.getMessage(), e);
- throw new StorageProviderException("s3Client download exception", e);
+ log.error("[{}] download exception: {}", this.config.getProvider(), e.getMessage(), e);
+ throw new StorageProviderException("download exception", e);
}
}
- private String getBucket() {
- String bucket = "";
- if (this.config instanceof AliYunOssStorage.Config) {
- bucket = ((AliYunOssStorage.Config) this.config).getBucket();
+ private Region getRegion() {
+ if (StringUtils.isNotBlank(s3Config.getRegion())) {
+ return Region.of(s3Config.getRegion());
}
- // MiniO
- else if (this.config instanceof MinIoStorage.Config) {
- bucket = ((MinIoStorage.Config) this.config).getBucket();
- }
- // 七牛云
- else if (this.config instanceof QiNiuKodoStorage.Config) {
- bucket = ((QiNiuKodoStorage.Config) this.config).getBucket();
- }
- // 腾讯云
- else if (this.config instanceof TencentCosStorage.Config) {
- bucket = ((TencentCosStorage.Config) this.config).getBucket();
- }
- // 错误
- else {
- throw new StorageProviderException("getBucket exception");
- }
- return bucket;
+ return Region.AWS_GLOBAL;
+ }
+
+ @EqualsAndHashCode(callSuper = true)
+ @Data
+ public static class Config extends StorageConfig.Config {
+
+ /**
+ * AccessKeyId
+ */
+ @NotEmpty(message = "AccessKeyId不能为空")
+ private String accessKeyId;
+
+ /**
+ * SecretAccessKey
+ */
+ @JsonPropertyEncrypt
+ @NotEmpty(message = "SecretAccessKey不能为空")
+ private String secretAccessKey;
+
+ /**
+ * endpoint
+ */
+ @URL(message = "Endpoint格式不正确", regexp = URL_REGEXP)
+ @NotEmpty(message = "Endpoint不能为空")
+ private String endpoint;
+
+ /**
+ * bucket
+ */
+ @NotEmpty(message = "Bucket不能为空")
+ private String bucket;
+
+ /**
+ * Region
+ */
+ private String region;
}
}
diff --git a/eiam-console/src/main/console-fe/src/pages/setting/Storage/StorageProvider.tsx b/eiam-console/src/main/console-fe/src/pages/setting/Storage/StorageProvider.tsx
index 67847f09..60519887 100644
--- a/eiam-console/src/main/console-fe/src/pages/setting/Storage/StorageProvider.tsx
+++ b/eiam-console/src/main/console-fe/src/pages/setting/Storage/StorageProvider.tsx
@@ -32,6 +32,7 @@ import AliCloudOss from './components/AliCloud';
import MinIO from './components/MinIo';
import QiQiuKodo from './components/QiNiu';
import TencentCos from './components/Tencent';
+import S3 from './components/S3';
import { Container } from '@/components/Container';
import { useIntl } from '@umijs/max';
@@ -239,12 +240,19 @@ const Storage = () => {
id: 'pages.setting.storage_provider.provider.minio',
}),
},
+ {
+ value: OssProvider.S3,
+ label: intl.formatMessage({
+ id: 'pages.setting.storage_provider.provider.s3',
+ }),
+ },
]}
/>
{provider === OssProvider.ALIYUN_OSS && }
{provider === OssProvider.TENCENT_COS && }
{provider === OssProvider.QINIU_KODO && }
{provider === OssProvider.MINIO && }
+ {provider === OssProvider.S3 && }
>
)}
diff --git a/eiam-console/src/main/console-fe/src/pages/setting/Storage/components/S3/index.tsx b/eiam-console/src/main/console-fe/src/pages/setting/Storage/components/S3/index.tsx
new file mode 100644
index 00000000..23580e02
--- /dev/null
+++ b/eiam-console/src/main/console-fe/src/pages/setting/Storage/components/S3/index.tsx
@@ -0,0 +1,120 @@
+/*
+ * eiam-console - Employee Identity and Access Management
+ * Copyright © 2022-Present Jinan Yuanchuang Network Technology Co., Ltd. (support@topiam.cn)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+import { ProFormText } from '@ant-design/pro-components';
+import { useIntl } from '@umijs/max';
+
+export default () => {
+ const intl = useIntl();
+ return (
+ <>
+
+
+
+
+
+
+ >
+ );
+};
diff --git a/eiam-console/src/main/console-fe/src/pages/setting/Storage/constant.ts b/eiam-console/src/main/console-fe/src/pages/setting/Storage/constant.ts
index 041547e3..bee29a72 100644
--- a/eiam-console/src/main/console-fe/src/pages/setting/Storage/constant.ts
+++ b/eiam-console/src/main/console-fe/src/pages/setting/Storage/constant.ts
@@ -26,6 +26,7 @@ export enum OssProvider {
QINIU_KODO = 'qiniu_kodo',
LOCAL = 'local',
MINIO = 'minio',
+ S3 = 's3',
}
export enum Language {
ZH = 'zh',
diff --git a/eiam-console/src/main/console-fe/src/pages/setting/Storage/locales/zh-CN.ts b/eiam-console/src/main/console-fe/src/pages/setting/Storage/locales/zh-CN.ts
index 39699ffb..90318df8 100644
--- a/eiam-console/src/main/console-fe/src/pages/setting/Storage/locales/zh-CN.ts
+++ b/eiam-console/src/main/console-fe/src/pages/setting/Storage/locales/zh-CN.ts
@@ -97,4 +97,29 @@ export default {
'pages.setting.storage_provider.minio.endpoint.rule.0.message': 'MinIO Endpoint为必填项',
'pages.setting.storage_provider.minio.bucket.placeholder': '请输入MinIO Bucket',
'pages.setting.storage_provider.minio.bucket.rule.0.message': 'MinIO Bucket为必填项',
+ 'pages.setting.storage_provider.provider.s3': 'S3',
+ 'pages.setting.storage_provider.provider.s3.endpoint': 'S3 域名',
+ 'pages.setting.storage_provider.provider.s3.endpoint.placeholder':
+ '请输入 S3 域名',
+ 'pages.setting.storage_provider.provider.qiniu_kodo.endpoint.rule.0.message':
+ '七牛云Kodo S3 域名为必填项',
+ 'pages.setting.storage_provider.provider.s3.domain': '外链域名',
+ 'pages.setting.storage_provider.provider.s3.domain.placeholder':
+ '请输入S3 外链域名',
+ 'pages.setting.storage_provider.provider.s3.domain.rule.0.message':
+ 'S3 外链域名为必填项',
+ 'pages.setting.storage_provider.provider.s3.access_key_id.placeholder':
+ '请输入S3 AccessKeyId',
+ 'pages.setting.storage_provider.provider.s3.access_key_id.rule.0.message':
+ 'S3 AccessKeyId为必填项',
+ 'pages.setting.storage_provider.provider.s3.secret_access_key.placeholder':
+ '请输入S3 SecretAccessKey',
+ 'pages.setting.storage_provider.provider.s3.secret_access_key.rule.0.message':
+ 'S3 SecretAccessKey为必填项',
+ 'pages.setting.storage_provider.provider.s3.region.placeholder':
+ '请输入S3 Region',
+ 'pages.setting.storage_provider.provider.s3.bucket.placeholder':
+ '请输入S3 Bucket',
+ 'pages.setting.storage_provider.provider.s3.bucket.rule.0.message':
+ 'S3 Bucket为必填项',
};
diff --git a/eiam-console/src/main/java/cn/topiam/employee/console/converter/setting/StorageSettingConverter.java b/eiam-console/src/main/java/cn/topiam/employee/console/converter/setting/StorageSettingConverter.java
index f934ed0a..273d247f 100644
--- a/eiam-console/src/main/java/cn/topiam/employee/console/converter/setting/StorageSettingConverter.java
+++ b/eiam-console/src/main/java/cn/topiam/employee/console/converter/setting/StorageSettingConverter.java
@@ -33,10 +33,7 @@ import cn.topiam.employee.common.jackjson.encrypt.EncryptionModule;
import cn.topiam.employee.common.storage.StorageConfig;
import cn.topiam.employee.common.storage.StorageProviderException;
import cn.topiam.employee.common.storage.enums.StorageProvider;
-import cn.topiam.employee.common.storage.impl.AliYunOssStorage;
-import cn.topiam.employee.common.storage.impl.MinIoStorage;
-import cn.topiam.employee.common.storage.impl.QiNiuKodoStorage;
-import cn.topiam.employee.common.storage.impl.TencentCosStorage;
+import cn.topiam.employee.common.storage.impl.*;
import cn.topiam.employee.console.pojo.result.setting.StorageProviderConfigResult;
import cn.topiam.employee.console.pojo.save.setting.StorageConfigSaveParam;
import cn.topiam.employee.support.validation.ValidationUtils;
@@ -120,6 +117,21 @@ public interface StorageSettingConverter {
unencryptedConfig.setSecretKey(param.getConfig().getString("secretKey"));
checkStorage(MinIoStorage::new, unencryptedConfig);
}
+ //S3
+ else if (provider.equals(StorageProvider.S3)) {
+ S3Storage.Config config = objectMapper.readValue(param.getConfig().toJSONString(),
+ S3Storage.Config.class);
+ config.setEndpoint(getUrl(config.getEndpoint()));
+ config.setDomain(getUrl(config.getDomain()));
+ builder.config(config);
+ validateEntity(ValidationUtils.validateEntity(config));
+
+ S3Storage.Config unencryptedConfig = new S3Storage.Config();
+ BeanUtils.copyProperties(config, unencryptedConfig);
+ unencryptedConfig
+ .setSecretAccessKey(param.getConfig().getString("secretAccessKey"));
+ checkStorage(S3Storage::new, unencryptedConfig);
+ }
entity.setName(STORAGE_PROVIDER_KEY);
// 指定序列化输入的类型
objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(),
diff --git a/eiam-portal/src/main/java/cn/topiam/employee/portal/controller/AppAccountController.java b/eiam-portal/src/main/java/cn/topiam/employee/portal/controller/AppAccountController.java
new file mode 100644
index 00000000..687503f4
--- /dev/null
+++ b/eiam-portal/src/main/java/cn/topiam/employee/portal/controller/AppAccountController.java
@@ -0,0 +1,105 @@
+/*
+ * eiam-portal - Employee Identity and Access Management
+ * Copyright © 2022-Present Jinan Yuanchuang Network Technology Co., Ltd. (support@topiam.cn)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package cn.topiam.employee.portal.controller;
+
+import org.springframework.http.MediaType;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import cn.topiam.employee.application.AppAccount;
+import cn.topiam.employee.audit.annotation.Audit;
+import cn.topiam.employee.audit.event.type.EventType;
+import cn.topiam.employee.portal.pojo.request.AppAccountRequest;
+import cn.topiam.employee.portal.service.AppAccountService;
+import cn.topiam.employee.support.lock.Lock;
+import cn.topiam.employee.support.preview.Preview;
+import cn.topiam.employee.support.result.ApiRestResult;
+
+import lombok.AllArgsConstructor;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import static cn.topiam.employee.common.constant.AppConstants.APP_PATH;
+
+/**
+ * 应用账户资源
+ *
+ * @author TopIAM
+ * Created by support@topiam.cn on 2022/6/4 21:06
+ */
+@Validated
+@Tag(name = "应用账户")
+@RestController
+@AllArgsConstructor
+@RequestMapping(value = APP_PATH + "/account", produces = MediaType.APPLICATION_JSON_VALUE)
+public class AppAccountController {
+
+ /**
+ * 获取应用账户列表
+ *
+ * @param appId {@link String}
+ * @return {@link }
+ */
+ @Operation(summary = "获取应用账户")
+ @GetMapping("/appId/{appId}")
+ public ApiRestResult getAppAccountList(@PathVariable String appId) {
+ AppAccount appAccount = appAccountService.getAppAccount(Long.valueOf(appId));
+ return ApiRestResult.ok(appAccount);
+ }
+
+ /**
+ * 创建应用账户
+ *
+ * @param param {@link AppAccountRequest}
+ * @return {@link Boolean}
+ */
+ @Lock
+ @Preview
+ @Operation(summary = "创建应用账户")
+ @Audit(type = EventType.ADD_APP_ACCOUNT)
+ @PostMapping(value = "/create")
+ @PreAuthorize(value = "authenticated and @sae.hasAuthority(T(cn.topiam.employee.support.security.userdetails.UserType).ADMIN)")
+ public ApiRestResult createAppAccount(@RequestBody @Validated AppAccountRequest param) {
+ return ApiRestResult. builder().result(appAccountService.createAppAccount(param))
+ .build();
+ }
+
+ /**
+ * 删除应用账户
+ *
+ * @param id {@link String}
+ * @return {@link Boolean}
+ */
+ @Lock
+ @Preview
+ @Operation(summary = "删除应用账户")
+ @Audit(type = EventType.DELETE_APP_ACCOUNT)
+ @DeleteMapping(value = "/delete/{id}")
+ @PreAuthorize(value = "authenticated and @sae.hasAuthority(T(cn.topiam.employee.support.security.userdetails.UserType).ADMIN)")
+ public ApiRestResult deleteAppAccount(@PathVariable(value = "id") String id) {
+ return ApiRestResult. builder().result(appAccountService.deleteAppAccount(id))
+ .build();
+ }
+
+ /**
+ * AppAccountService
+ */
+ private final AppAccountService appAccountService;
+
+}
diff --git a/eiam-portal/src/main/java/cn/topiam/employee/portal/converter/AppAccountConverter.java b/eiam-portal/src/main/java/cn/topiam/employee/portal/converter/AppAccountConverter.java
new file mode 100644
index 00000000..1c6b4598
--- /dev/null
+++ b/eiam-portal/src/main/java/cn/topiam/employee/portal/converter/AppAccountConverter.java
@@ -0,0 +1,51 @@
+/*
+ * eiam-portal - Employee Identity and Access Management
+ * Copyright © 2022-Present Jinan Yuanchuang Network Technology Co., Ltd. (support@topiam.cn)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package cn.topiam.employee.portal.converter;
+
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+
+import cn.topiam.employee.common.entity.app.AppAccountEntity;
+import cn.topiam.employee.portal.pojo.request.AppAccountRequest;
+
+/**
+ * 应用账户映射
+ *
+ * @author TopIAM
+ * Created by support@topiam.cn on 2023/8/25 21:08
+ */
+@Mapper(componentModel = "spring")
+public interface AppAccountConverter {
+
+ /**
+ * 应用账户新增参数转换应用账户实体
+ *
+ * @param param {@link AppAccountRequest}
+ * @return {@link AppAccountEntity}
+ */
+ @Mapping(target = "userId", ignore = true)
+ @Mapping(target = "deleted", ignore = true)
+ @Mapping(target = "remark", ignore = true)
+ @Mapping(target = "id", ignore = true)
+ @Mapping(target = "updateTime", ignore = true)
+ @Mapping(target = "updateBy", ignore = true)
+ @Mapping(target = "createTime", ignore = true)
+ @Mapping(target = "createBy", ignore = true)
+ AppAccountEntity appAccountRequestConvertToEntity(AppAccountRequest param);
+
+}
diff --git a/eiam-portal/src/main/java/cn/topiam/employee/portal/pojo/request/AppAccountRequest.java b/eiam-portal/src/main/java/cn/topiam/employee/portal/pojo/request/AppAccountRequest.java
new file mode 100644
index 00000000..120f91fe
--- /dev/null
+++ b/eiam-portal/src/main/java/cn/topiam/employee/portal/pojo/request/AppAccountRequest.java
@@ -0,0 +1,55 @@
+/*
+ * eiam-portal - Employee Identity and Access Management
+ * Copyright © 2022-Present Jinan Yuanchuang Network Technology Co., Ltd. (support@topiam.cn)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package cn.topiam.employee.portal.pojo.request;
+
+import lombok.Data;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+
+/**
+ * AppAccountRequest 应用账户新增入参
+ *
+ * @author TopIAM
+ * Created by support@topiam.cn on 2023/8/25 22:13
+ */
+@Data
+@Schema(description = "应用账户新增入参")
+public class AppAccountRequest {
+
+ /**
+ * 应用ID
+ */
+ @Schema(description = "应用ID")
+ @NotNull(message = "应用ID不能为空")
+ private Long appId;
+
+ /**
+ * 账户名称
+ */
+ @Schema(description = "账户名称")
+ @NotBlank(message = "账户名称不能为空")
+ private String account;
+
+ /**
+ * 账户密码
+ */
+ @Schema(description = "账户密码")
+ private String password;
+}
diff --git a/eiam-portal/src/main/java/cn/topiam/employee/portal/service/AppAccountService.java b/eiam-portal/src/main/java/cn/topiam/employee/portal/service/AppAccountService.java
new file mode 100644
index 00000000..782085a0
--- /dev/null
+++ b/eiam-portal/src/main/java/cn/topiam/employee/portal/service/AppAccountService.java
@@ -0,0 +1,53 @@
+/*
+ * eiam-portal - Employee Identity and Access Management
+ * Copyright © 2022-Present Jinan Yuanchuang Network Technology Co., Ltd. (support@topiam.cn)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package cn.topiam.employee.portal.service;
+
+import cn.topiam.employee.application.AppAccount;
+import cn.topiam.employee.portal.pojo.request.AppAccountRequest;
+
+/**
+ * 应用账户
+ *
+ * @author TopIAM
+ * Created by support@topiam.cn on 2023/8/25 21:07
+ */
+public interface AppAccountService {
+
+ /**
+ * 新增应用账户
+ *
+ * @param param {@link AppAccountRequest}
+ * @return {@link Boolean}
+ */
+ Boolean createAppAccount(AppAccountRequest param);
+
+ /**
+ * 删除应用账户
+ *
+ * @param id {@link String}
+ * @return {@link Boolean}
+ */
+ Boolean deleteAppAccount(String id);
+
+ /**
+ * 获取应用账户
+ * @param appId {@link Long}
+ * @return {@link AppAccount}
+ */
+ AppAccount getAppAccount(Long appId);
+}
diff --git a/eiam-portal/src/main/java/cn/topiam/employee/portal/service/impl/AppAccountServiceImpl.java b/eiam-portal/src/main/java/cn/topiam/employee/portal/service/impl/AppAccountServiceImpl.java
new file mode 100644
index 00000000..b9f6488a
--- /dev/null
+++ b/eiam-portal/src/main/java/cn/topiam/employee/portal/service/impl/AppAccountServiceImpl.java
@@ -0,0 +1,134 @@
+/*
+ * eiam-portal - Employee Identity and Access Management
+ * Copyright © 2022-Present Jinan Yuanchuang Network Technology Co., Ltd. (support@topiam.cn)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package cn.topiam.employee.portal.service.impl;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Optional;
+
+import org.apache.commons.codec.binary.Base64;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.alibaba.excel.util.StringUtils;
+
+import cn.topiam.employee.application.AppAccount;
+import cn.topiam.employee.audit.context.AuditContext;
+import cn.topiam.employee.audit.entity.Target;
+import cn.topiam.employee.audit.enums.TargetType;
+import cn.topiam.employee.common.entity.app.AppAccountEntity;
+import cn.topiam.employee.common.exception.app.AppAccountExistException;
+import cn.topiam.employee.common.jackjson.encrypt.EncryptContextHelp;
+import cn.topiam.employee.common.repository.app.AppAccountRepository;
+import cn.topiam.employee.portal.converter.AppAccountConverter;
+import cn.topiam.employee.portal.pojo.request.AppAccountRequest;
+import cn.topiam.employee.portal.service.AppAccountService;
+import cn.topiam.employee.support.exception.TopIamException;
+import cn.topiam.employee.support.security.util.SecurityUtils;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * 应用账户
+ *
+ * @author TopIAM
+ * Created by support@topiam.cn on 2023/8/25 21:07
+ */
+@Service
+@Slf4j
+@AllArgsConstructor
+public class AppAccountServiceImpl implements AppAccountService {
+
+ /**
+ * 新增应用账户
+ *
+ * @param param {@link AppAccountRequest}
+ * @return {@link Boolean}
+ */
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Boolean createAppAccount(AppAccountRequest param) {
+ Optional optional = appAccountRepository
+ .findByAppIdAndUserId(param.getAppId(), Long.valueOf(SecurityUtils.getCurrentUserId()));
+ if (optional.isPresent()) {
+ throw new AppAccountExistException();
+ }
+ AppAccountEntity entity = appAccountConverter.appAccountRequestConvertToEntity(param);
+ //密码不为空
+ if (!StringUtils.isBlank(param.getPassword())) {
+ Base64 base64 = new Base64();
+ String password = new String(base64.decode(param.getPassword()),
+ StandardCharsets.UTF_8);
+ entity.setPassword(EncryptContextHelp.encrypt(password));
+ }
+ appAccountRepository.save(entity);
+ AuditContext.setTarget(
+ Target.builder().id(entity.getUserId().toString()).type(TargetType.USER).build(),
+ Target.builder().id(entity.getAccount()).type(TargetType.APPLICATION_ACCOUNT).build(),
+ Target.builder().id(entity.getAppId().toString()).type(TargetType.APPLICATION).build());
+ return true;
+ }
+
+ /**
+ * 删除应用账户
+ *
+ * @param id {@link Long}
+ * @return {@link String}
+ */
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Boolean deleteAppAccount(String id) {
+ Optional optional = appAccountRepository.findById(Long.valueOf(id));
+ //管理员不存在
+ if (optional.isEmpty()) {
+ AuditContext.setContent("删除失败,应用账户不存在");
+ log.warn(AuditContext.getContent());
+ throw new TopIamException(AuditContext.getContent());
+ }
+ appAccountRepository.deleteById(Long.valueOf(id));
+ AuditContext.setTarget(
+ Target.builder().id(optional.get().getId().toString()).type(TargetType.USER).build(),
+ Target.builder().id(optional.get().getAppId().toString()).type(TargetType.APPLICATION)
+ .build());
+ return true;
+ }
+
+ @Override
+ public AppAccount getAppAccount(Long appId) {
+ Optional optional = appAccountRepository.findByAppIdAndUserId(appId,
+ Long.valueOf(SecurityUtils.getCurrentUserId()));
+ if (optional.isPresent()) {
+ AppAccountEntity entity = optional.get();
+ AppAccount account = new AppAccount();
+ account.setAppId(entity.getAppId());
+ account.setAccount(entity.getAccount());
+ return account;
+ }
+ return null;
+ }
+
+ /**
+ * AppAccountConverter
+ */
+ private final AppAccountConverter appAccountConverter;
+
+ /**
+ * AppAccountRepository
+ */
+ private final AppAccountRepository appAccountRepository;
+}