mirror of https://gitee.com/topiam/eiam
存储配置支持S3
parent
c56ca78793
commit
264febf4b3
|
@ -51,7 +51,11 @@ public enum StorageProvider implements Serializable {
|
||||||
/**
|
/**
|
||||||
* minio
|
* minio
|
||||||
*/
|
*/
|
||||||
MINIO("minio", "minio", MinIoStorage.class);
|
MINIO("minio", "minio", MinIoStorage.class),
|
||||||
|
/**
|
||||||
|
* S3
|
||||||
|
*/
|
||||||
|
S3("s3", "s3", S3Storage.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* code
|
* code
|
||||||
|
|
|
@ -17,25 +17,36 @@
|
||||||
*/
|
*/
|
||||||
package cn.topiam.employee.common.storage.impl;
|
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.AbstractStorage;
|
||||||
import cn.topiam.employee.common.storage.StorageConfig;
|
import cn.topiam.employee.common.storage.StorageConfig;
|
||||||
import cn.topiam.employee.common.storage.StorageProviderException;
|
import cn.topiam.employee.common.storage.StorageProviderException;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
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.AwsBasicCredentials;
|
||||||
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
|
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
|
||||||
import software.amazon.awssdk.core.sync.RequestBody;
|
import software.amazon.awssdk.core.sync.RequestBody;
|
||||||
import software.amazon.awssdk.core.waiters.WaiterResponse;
|
|
||||||
import software.amazon.awssdk.regions.Region;
|
import software.amazon.awssdk.regions.Region;
|
||||||
import software.amazon.awssdk.services.s3.S3Client;
|
import software.amazon.awssdk.services.s3.S3Client;
|
||||||
import software.amazon.awssdk.services.s3.model.*;
|
import software.amazon.awssdk.services.s3.model.*;
|
||||||
import software.amazon.awssdk.services.s3.waiters.S3Waiter;
|
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
|
||||||
|
import software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest;
|
||||||
import java.io.InputStream;
|
import software.amazon.awssdk.services.s3.presigner.model.PresignedGetObjectRequest;
|
||||||
import java.net.URI;
|
import static cn.topiam.employee.common.constant.StorageConstants.URL_REGEXP;
|
||||||
import java.net.URL;
|
|
||||||
import java.net.URLEncoder;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* S3 协议实现
|
* S3 协议实现
|
||||||
|
@ -46,86 +57,55 @@ import java.nio.charset.StandardCharsets;
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class S3Storage extends AbstractStorage {
|
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) {
|
public S3Storage(StorageConfig config) {
|
||||||
super(config);
|
super(config);
|
||||||
// 创建连接
|
// 获取客户端
|
||||||
|
this.s3Config = (Config) this.config.getConfig();
|
||||||
// 凭证
|
this.s3Client = getS3Client();
|
||||||
AwsBasicCredentials creds;
|
this.s3Presigner = getS3Presigner();
|
||||||
this.config = config.getConfig();
|
createBucket();
|
||||||
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 {
|
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 {
|
try {
|
||||||
// 创建bucket
|
|
||||||
S3Waiter s3Waiter = this.s3Client.waiter();
|
|
||||||
CreateBucketRequest bucketRequest = CreateBucketRequest.builder().bucket(bucket).build();
|
|
||||||
// 获取bucket是否存在
|
// 获取bucket是否存在
|
||||||
this.s3Client.createBucket(bucketRequest);
|
HeadBucketRequest bucketRequestWait = HeadBucketRequest.builder()
|
||||||
HeadBucketRequest bucketRequestWait = HeadBucketRequest.builder().bucket(bucket).build();
|
.bucket(this.s3Config.getBucket()).build();
|
||||||
WaiterResponse<HeadBucketResponse> waiterResponse = s3Waiter
|
s3Client.headBucket(bucketRequestWait);
|
||||||
.waitUntilBucketExists(bucketRequestWait);
|
} catch (S3Exception se) {
|
||||||
waiterResponse.matched().response().ifPresent(System.out::println);
|
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) {
|
} catch (Exception e) {
|
||||||
log.error("create bucket exception: {}", e.getMessage(), e);
|
log.error("create bucket exception: {}", e.getMessage(), e);
|
||||||
throw new StorageProviderException("create bucket exception", e);
|
throw new StorageProviderException("create bucket exception", e);
|
||||||
|
@ -136,57 +116,76 @@ public class S3Storage extends AbstractStorage {
|
||||||
public String upload(@NotNull String fileName,
|
public String upload(@NotNull String fileName,
|
||||||
InputStream inputStream) throws StorageProviderException {
|
InputStream inputStream) throws StorageProviderException {
|
||||||
try {
|
try {
|
||||||
super.upload(fileName, inputStream);
|
String key = s3Config.getLocation() + SEPARATOR + getFileName(fileName);
|
||||||
String bucket = getBucket();
|
PutObjectRequest putOb = PutObjectRequest.builder().bucket(s3Config.getBucket())
|
||||||
String key = this.config.getLocation() + SEPARATOR + getFileName(fileName);
|
.key(key).build();
|
||||||
// 写object
|
this.s3Client.putObject(putOb, RequestBody.fromBytes(inputStream.readAllBytes()));
|
||||||
PutObjectRequest putOb = PutObjectRequest.builder().bucket(bucket).key(key).build();
|
return this.s3Config.getDomain() + SEPARATOR
|
||||||
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");
|
+ URLEncoder.encode(key, StandardCharsets.UTF_8).replaceAll("\\+", "%20");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("s3Client upload exception: {}", e.getMessage(), e);
|
log.error("[{}] upload exception: {}", this.config.getProvider(), e.getMessage(), e);
|
||||||
throw new StorageProviderException("s3Client upload exception", e);
|
throw new StorageProviderException("upload exception", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String download(String path) throws StorageProviderException {
|
public String download(String path) throws StorageProviderException {
|
||||||
try {
|
try {
|
||||||
super.download(path);
|
GetObjectRequest getObjectRequest = GetObjectRequest.builder()
|
||||||
String bucket = getBucket();
|
.bucket(this.s3Config.getBucket()).key(path).build();
|
||||||
GetUrlRequest request = GetUrlRequest.builder().bucket(bucket).key(path).build();
|
GetObjectPresignRequest getObjectPresignRequest = GetObjectPresignRequest.builder()
|
||||||
|
.signatureDuration(Duration.ofSeconds(EXPIRY_SECONDS))
|
||||||
URL url = this.s3Client.utilities().getUrl(request);
|
.getObjectRequest(getObjectRequest).build();
|
||||||
return url.toString();
|
PresignedGetObjectRequest presignedGetObjectRequest = s3Presigner
|
||||||
|
.presignGetObject(getObjectPresignRequest);
|
||||||
|
String downloadUrl = presignedGetObjectRequest.url().toString();
|
||||||
|
return downloadUrl.replace(this.s3Config.getEndpoint(), this.s3Config.getDomain());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("s3Client download exception: {}", e.getMessage(), e);
|
log.error("[{}] download exception: {}", this.config.getProvider(), e.getMessage(), e);
|
||||||
throw new StorageProviderException("s3Client download exception", e);
|
throw new StorageProviderException("download exception", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getBucket() {
|
private Region getRegion() {
|
||||||
String bucket = "";
|
if (StringUtils.isNotBlank(s3Config.getRegion())) {
|
||||||
if (this.config instanceof AliYunOssStorage.Config) {
|
return Region.of(s3Config.getRegion());
|
||||||
bucket = ((AliYunOssStorage.Config) this.config).getBucket();
|
|
||||||
}
|
}
|
||||||
// MiniO
|
return Region.AWS_GLOBAL;
|
||||||
else if (this.config instanceof MinIoStorage.Config) {
|
}
|
||||||
bucket = ((MinIoStorage.Config) this.config).getBucket();
|
|
||||||
}
|
@EqualsAndHashCode(callSuper = true)
|
||||||
// 七牛云
|
@Data
|
||||||
else if (this.config instanceof QiNiuKodoStorage.Config) {
|
public static class Config extends StorageConfig.Config {
|
||||||
bucket = ((QiNiuKodoStorage.Config) this.config).getBucket();
|
|
||||||
}
|
/**
|
||||||
// 腾讯云
|
* AccessKeyId
|
||||||
else if (this.config instanceof TencentCosStorage.Config) {
|
*/
|
||||||
bucket = ((TencentCosStorage.Config) this.config).getBucket();
|
@NotEmpty(message = "AccessKeyId不能为空")
|
||||||
}
|
private String accessKeyId;
|
||||||
// 错误
|
|
||||||
else {
|
/**
|
||||||
throw new StorageProviderException("getBucket exception");
|
* SecretAccessKey
|
||||||
}
|
*/
|
||||||
return bucket;
|
@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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ import AliCloudOss from './components/AliCloud';
|
||||||
import MinIO from './components/MinIo';
|
import MinIO from './components/MinIo';
|
||||||
import QiQiuKodo from './components/QiNiu';
|
import QiQiuKodo from './components/QiNiu';
|
||||||
import TencentCos from './components/Tencent';
|
import TencentCos from './components/Tencent';
|
||||||
|
import S3 from './components/S3';
|
||||||
import { Container } from '@/components/Container';
|
import { Container } from '@/components/Container';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
|
|
||||||
|
@ -239,12 +240,19 @@ const Storage = () => {
|
||||||
id: 'pages.setting.storage_provider.provider.minio',
|
id: 'pages.setting.storage_provider.provider.minio',
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
value: OssProvider.S3,
|
||||||
|
label: intl.formatMessage({
|
||||||
|
id: 'pages.setting.storage_provider.provider.s3',
|
||||||
|
}),
|
||||||
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
{provider === OssProvider.ALIYUN_OSS && <AliCloudOss />}
|
{provider === OssProvider.ALIYUN_OSS && <AliCloudOss />}
|
||||||
{provider === OssProvider.TENCENT_COS && <TencentCos />}
|
{provider === OssProvider.TENCENT_COS && <TencentCos />}
|
||||||
{provider === OssProvider.QINIU_KODO && <QiQiuKodo />}
|
{provider === OssProvider.QINIU_KODO && <QiQiuKodo />}
|
||||||
{provider === OssProvider.MINIO && <MinIO />}
|
{provider === OssProvider.MINIO && <MinIO />}
|
||||||
|
{provider === OssProvider.S3 && <S3 />}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</ProForm>
|
</ProForm>
|
||||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
import { ProFormText } from '@ant-design/pro-components';
|
||||||
|
import { useIntl } from '@umijs/max';
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
const intl = useIntl();
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ProFormText
|
||||||
|
name={['config', 'domain']}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
id: 'pages.setting.storage_provider.provider.s3.domain',
|
||||||
|
})}
|
||||||
|
placeholder={intl.formatMessage({
|
||||||
|
id: 'pages.setting.storage_provider.provider.s3.domain.placeholder',
|
||||||
|
})}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: intl.formatMessage({
|
||||||
|
id: 'pages.setting.storage_provider.provider.s3.domain.rule.0.message',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
fieldProps={{ autoComplete: 'off' }}
|
||||||
|
/>
|
||||||
|
<ProFormText
|
||||||
|
name={['config', 'endpoint']}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
id: 'pages.setting.storage_provider.provider.s3.endpoint',
|
||||||
|
})}
|
||||||
|
placeholder={intl.formatMessage({
|
||||||
|
id: 'pages.setting.storage_provider.provider.s3.endpoint.placeholder',
|
||||||
|
})}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: intl.formatMessage({
|
||||||
|
id: 'pages.setting.storage_provider.provider.s3.endpoint.rule.0.message',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<ProFormText
|
||||||
|
name={['config', 'accessKeyId']}
|
||||||
|
label="AccessKeyId"
|
||||||
|
placeholder={intl.formatMessage({
|
||||||
|
id: 'pages.setting.storage_provider.provider.s3.access_key_id.placeholder',
|
||||||
|
})}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: intl.formatMessage({
|
||||||
|
id: 'pages.setting.storage_provider.provider.s3.access_key_id.rule.0.message',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
fieldProps={{
|
||||||
|
autoComplete: 'new-password',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<ProFormText.Password
|
||||||
|
name={['config', 'secretAccessKey']}
|
||||||
|
label="SecretAccessKey"
|
||||||
|
placeholder={intl.formatMessage({
|
||||||
|
id: 'pages.setting.storage_provider.provider.s3.secret_access_key.placeholder',
|
||||||
|
})}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: intl.formatMessage({
|
||||||
|
id: 'pages.setting.storage_provider.provider.s3.secret_access_key.rule.0.message',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
fieldProps={{ autoComplete: 'off' }}
|
||||||
|
/>
|
||||||
|
<ProFormText
|
||||||
|
name={['config', 'bucket']}
|
||||||
|
label={'Bucket'}
|
||||||
|
placeholder={intl.formatMessage({
|
||||||
|
id: 'pages.setting.storage_provider.provider.s3.bucket.placeholder',
|
||||||
|
})}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: intl.formatMessage({
|
||||||
|
id: 'pages.setting.storage_provider.provider.s3.bucket.rule.0.message',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
fieldProps={{ autoComplete: 'off' }}
|
||||||
|
/>
|
||||||
|
<ProFormText
|
||||||
|
name={['config', 'region']}
|
||||||
|
label={'Region'}
|
||||||
|
placeholder={intl.formatMessage({
|
||||||
|
id: 'pages.setting.storage_provider.provider.s3.region.placeholder',
|
||||||
|
})}
|
||||||
|
fieldProps={{ autoComplete: 'off' }}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
|
@ -26,6 +26,7 @@ export enum OssProvider {
|
||||||
QINIU_KODO = 'qiniu_kodo',
|
QINIU_KODO = 'qiniu_kodo',
|
||||||
LOCAL = 'local',
|
LOCAL = 'local',
|
||||||
MINIO = 'minio',
|
MINIO = 'minio',
|
||||||
|
S3 = 's3',
|
||||||
}
|
}
|
||||||
export enum Language {
|
export enum Language {
|
||||||
ZH = 'zh',
|
ZH = 'zh',
|
||||||
|
|
|
@ -97,4 +97,29 @@ export default {
|
||||||
'pages.setting.storage_provider.minio.endpoint.rule.0.message': 'MinIO Endpoint为必填项',
|
'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.placeholder': '请输入MinIO Bucket',
|
||||||
'pages.setting.storage_provider.minio.bucket.rule.0.message': '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为必填项',
|
||||||
};
|
};
|
||||||
|
|
|
@ -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.StorageConfig;
|
||||||
import cn.topiam.employee.common.storage.StorageProviderException;
|
import cn.topiam.employee.common.storage.StorageProviderException;
|
||||||
import cn.topiam.employee.common.storage.enums.StorageProvider;
|
import cn.topiam.employee.common.storage.enums.StorageProvider;
|
||||||
import cn.topiam.employee.common.storage.impl.AliYunOssStorage;
|
import cn.topiam.employee.common.storage.impl.*;
|
||||||
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.console.pojo.result.setting.StorageProviderConfigResult;
|
import cn.topiam.employee.console.pojo.result.setting.StorageProviderConfigResult;
|
||||||
import cn.topiam.employee.console.pojo.save.setting.StorageConfigSaveParam;
|
import cn.topiam.employee.console.pojo.save.setting.StorageConfigSaveParam;
|
||||||
import cn.topiam.employee.support.validation.ValidationUtils;
|
import cn.topiam.employee.support.validation.ValidationUtils;
|
||||||
|
@ -120,6 +117,21 @@ public interface StorageSettingConverter {
|
||||||
unencryptedConfig.setSecretKey(param.getConfig().getString("secretKey"));
|
unencryptedConfig.setSecretKey(param.getConfig().getString("secretKey"));
|
||||||
checkStorage(MinIoStorage::new, unencryptedConfig);
|
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);
|
entity.setName(STORAGE_PROVIDER_KEY);
|
||||||
// 指定序列化输入的类型
|
// 指定序列化输入的类型
|
||||||
objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(),
|
objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(),
|
||||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
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<AppAccount> 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<Boolean> createAppAccount(@RequestBody @Validated AppAccountRequest param) {
|
||||||
|
return ApiRestResult.<Boolean> 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<Boolean> deleteAppAccount(@PathVariable(value = "id") String id) {
|
||||||
|
return ApiRestResult.<Boolean> builder().result(appAccountService.deleteAppAccount(id))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AppAccountService
|
||||||
|
*/
|
||||||
|
private final AppAccountService appAccountService;
|
||||||
|
|
||||||
|
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
|
||||||
|
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
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<AppAccountEntity> 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<AppAccountEntity> 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<AppAccountEntity> 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;
|
||||||
|
}
|
Loading…
Reference in New Issue