fix(数据源): 对返回数据源信息进行加密
This commit is contained in:
parent
5fee7c16e4
commit
bd3ec213df
@ -1149,8 +1149,12 @@ public class DatasourceServer implements DatasourceApi {
|
||||
params.add(apiDefinition);
|
||||
}
|
||||
}
|
||||
datasourceDTO.setApiConfigurationStr(new String(Base64.getEncoder().encode(Objects.requireNonNull(JsonUtil.toJSONString(apiDefinitionListWithStatus)).toString().getBytes())));
|
||||
datasourceDTO.setParamsStr(new String(Base64.getEncoder().encode(Objects.requireNonNull(JsonUtil.toJSONString(params)).toString().getBytes())));
|
||||
if(CollectionUtils.isNotEmpty(params)){
|
||||
datasourceDTO.setParamsStr(RsaUtils.symmetricEncrypt(JsonUtil.toJSONString(params).toString()));
|
||||
}
|
||||
if(CollectionUtils.isNotEmpty(apiDefinitionListWithStatus)){
|
||||
datasourceDTO.setApiConfigurationStr(RsaUtils.symmetricEncrypt(JsonUtil.toJSONString(apiDefinitionListWithStatus).toString()));
|
||||
}
|
||||
if (success == apiDefinitionList.size()) {
|
||||
datasourceDTO.setStatus("Success");
|
||||
} else {
|
||||
@ -1164,7 +1168,6 @@ public class DatasourceServer implements DatasourceApi {
|
||||
TaskDTO taskDTO = new TaskDTO();
|
||||
BeanUtils.copyBean(taskDTO, coreDatasourceTask);
|
||||
datasourceDTO.setSyncSetting(taskDTO);
|
||||
|
||||
CoreDatasourceTask task = datasourceTaskServer.selectByDSId(datasourceDTO.getId());
|
||||
if (task != null) {
|
||||
datasourceDTO.setLastSyncTime(task.getStartTime());
|
||||
@ -1174,13 +1177,12 @@ public class DatasourceServer implements DatasourceApi {
|
||||
Provider provider = ProviderFactory.getProvider(datasourceDTO.getType());
|
||||
provider.hidePW(datasourceDTO);
|
||||
}
|
||||
|
||||
}
|
||||
if (datasourceDTO.getType().equalsIgnoreCase(DatasourceConfiguration.DatasourceType.Excel.toString())) {
|
||||
datasourceDTO.setFileName(ExcelUtils.getFileName(datasource));
|
||||
datasourceDTO.setSize(ExcelUtils.getSize(datasource));
|
||||
}
|
||||
datasourceDTO.setConfiguration(new String(Base64.getEncoder().encode(datasourceDTO.getConfiguration().getBytes())));
|
||||
datasourceDTO.setConfiguration(RsaUtils.symmetricEncrypt(datasourceDTO.getConfiguration()));
|
||||
datasourceDTO.setCreator(coreUserManage.getUserName(Long.valueOf(datasourceDTO.getCreateBy())));
|
||||
return datasourceDTO;
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
package io.dataease.datasource.server;
|
||||
|
||||
import com.mchange.rmi.NotAuthorizedException;
|
||||
import io.dataease.api.ds.EngineApi;
|
||||
import io.dataease.datasource.dao.auto.entity.CoreDeEngine;
|
||||
import io.dataease.datasource.dao.auto.mapper.CoreDeEngineMapper;
|
||||
@ -11,6 +10,7 @@ import io.dataease.extensions.datasource.dto.DatasourceDTO;
|
||||
import io.dataease.utils.AuthUtils;
|
||||
import io.dataease.utils.BeanUtils;
|
||||
import io.dataease.utils.IDUtils;
|
||||
import io.dataease.utils.RsaUtils;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@ -41,7 +41,9 @@ public class EngineServer implements EngineApi {
|
||||
if (CollectionUtils.isEmpty(deEngines)) {
|
||||
return datasourceDTO;
|
||||
}
|
||||
return BeanUtils.copyBean(datasourceDTO, deEngines.get(0));
|
||||
BeanUtils.copyBean(datasourceDTO, deEngines.get(0));
|
||||
datasourceDTO.setConfiguration(RsaUtils.symmetricEncrypt(datasourceDTO.getConfiguration()));
|
||||
return datasourceDTO;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -23,6 +23,13 @@ public class RestIndexController {
|
||||
return RsaUtils.publicKey();
|
||||
}
|
||||
|
||||
@GetMapping("/symmetricKey")
|
||||
@ResponseBody
|
||||
public String symmetricKey() {
|
||||
return RsaUtils.generateSymmetricKey();
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/model")
|
||||
@ResponseBody
|
||||
public boolean model() {
|
||||
|
||||
@ -19,7 +19,7 @@ import java.util.List;
|
||||
@Component
|
||||
public class LinkInterceptor implements HandlerInterceptor {
|
||||
|
||||
private final static String whiteListText = "/user/ipInfo, /apisix/check, /datasetData/enumValue, /datasetData/enumValueObj, /datasetData/getFieldTree, /dekey, /share/validate, /sysParameter/queryOnlineMap, /chartData/innerExportDetails";
|
||||
private final static String whiteListText = "/user/ipInfo, /apisix/check, /datasetData/enumValue, /datasetData/enumValueObj, /datasetData/getFieldTree, /dekey, /symmetricKey, /share/validate, /sysParameter/queryOnlineMap, /chartData/innerExportDetails";
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
@ -4,6 +4,8 @@ export const loginApi = data => request.post({ url: '/login/localLogin', data })
|
||||
|
||||
export const queryDekey = () => request.get({ url: 'dekey' })
|
||||
|
||||
export const querySymmetricKey = () => request.get({ url: 'symmetricKey' })
|
||||
|
||||
export const modelApi = () => request.get({ url: 'model' })
|
||||
|
||||
export const platformLoginApi = origin => request.post({ url: '/login/platformLogin/' + origin })
|
||||
|
||||
@ -40,3 +40,15 @@ export const rsaEncryp = word => {
|
||||
crypt.setKey(pk)
|
||||
return crypt.encrypt(word)
|
||||
}
|
||||
|
||||
export const symmetricDecrypt = (data, keyStr) => {
|
||||
const iv = CryptoJS.enc.Utf8.parse('0000000000000000')
|
||||
const key = CryptoJS.enc.Base64.parse(keyStr)
|
||||
const decodedCiphertext = CryptoJS.enc.Base64.parse(data)
|
||||
const decrypted = CryptoJS.AES.decrypt({ ciphertext: decodedCiphertext }, key, {
|
||||
iv: iv,
|
||||
mode: CryptoJS.mode.CBC,
|
||||
padding: CryptoJS.pad.Pkcs7
|
||||
})
|
||||
return decrypted.toString(CryptoJS.enc.Utf8)
|
||||
}
|
||||
|
||||
@ -10,6 +10,8 @@ import { cloneDeep } from 'lodash-es'
|
||||
import { getDeEngine } from '@/api/datasource'
|
||||
import { CustomPassword } from '@/components/custom-password'
|
||||
import { Base64 } from 'js-base64'
|
||||
import { querySymmetricKey } from '@/api/login'
|
||||
import { symmetricDecrypt } from '@/utils/encryption'
|
||||
const { t } = useI18n()
|
||||
const dialogVisible = ref(false)
|
||||
const loadingInstance = ref(null)
|
||||
@ -149,45 +151,47 @@ const defaultInfo = {
|
||||
}
|
||||
const nodeInfo = reactive(cloneDeep(defaultInfo))
|
||||
const edit = () => {
|
||||
getDeEngine()
|
||||
.then(res => {
|
||||
let {
|
||||
name,
|
||||
createBy,
|
||||
id,
|
||||
createTime,
|
||||
creator,
|
||||
type,
|
||||
pid,
|
||||
configuration,
|
||||
syncSetting,
|
||||
fileName,
|
||||
size,
|
||||
description,
|
||||
lastSyncTime
|
||||
} = res.data
|
||||
if (configuration) {
|
||||
configuration = JSON.parse(configuration)
|
||||
}
|
||||
Object.assign(nodeInfo, {
|
||||
name,
|
||||
pid,
|
||||
description,
|
||||
fileName,
|
||||
size,
|
||||
createTime,
|
||||
creator,
|
||||
createBy,
|
||||
id,
|
||||
type,
|
||||
configuration,
|
||||
syncSetting,
|
||||
lastSyncTime
|
||||
querySymmetricKey().then(response => {
|
||||
getDeEngine()
|
||||
.then(res => {
|
||||
let {
|
||||
name,
|
||||
createBy,
|
||||
id,
|
||||
createTime,
|
||||
creator,
|
||||
type,
|
||||
pid,
|
||||
configuration,
|
||||
syncSetting,
|
||||
fileName,
|
||||
size,
|
||||
description,
|
||||
lastSyncTime
|
||||
} = res.data
|
||||
if (configuration) {
|
||||
configuration = JSON.parse(symmetricDecrypt(configuration, response.data))
|
||||
}
|
||||
Object.assign(nodeInfo, {
|
||||
name,
|
||||
pid,
|
||||
description,
|
||||
fileName,
|
||||
size,
|
||||
createTime,
|
||||
creator,
|
||||
createBy,
|
||||
id,
|
||||
type,
|
||||
configuration,
|
||||
syncSetting,
|
||||
lastSyncTime
|
||||
})
|
||||
})
|
||||
})
|
||||
.finally(() => {
|
||||
dialogVisible.value = true
|
||||
})
|
||||
.finally(() => {
|
||||
dialogVisible.value = true
|
||||
})
|
||||
})
|
||||
}
|
||||
const basicForm = ref()
|
||||
|
||||
|
||||
@ -42,6 +42,8 @@ import InfoTemplate from '@/views/system/common/InfoTemplate.vue'
|
||||
import { dsTypes } from '@/views/visualized/data/datasource/form/option'
|
||||
import { getDeEngine } from '@/api/datasource'
|
||||
import request from '@/config/axios'
|
||||
import { querySymmetricKey } from '@/api/login'
|
||||
import { symmetricDecrypt } from '@/utils/encryption'
|
||||
const { t } = useI18n()
|
||||
const typeMap = dsTypes.reduce((pre, next) => {
|
||||
pre[next.type] = next.name
|
||||
@ -54,82 +56,82 @@ const infoTemplateTime = ref()
|
||||
const templateList = ref<SettingRecord[]>([])
|
||||
const templateListTime = ref<SettingRecord[]>([])
|
||||
const getEngine = () => {
|
||||
getDeEngine().then(res => {
|
||||
let { id, type, configuration } = res.data
|
||||
if (configuration) {
|
||||
configuration = JSON.parse(configuration)
|
||||
}
|
||||
|
||||
nodeInfoId = id
|
||||
|
||||
templateListTime.value = [
|
||||
{
|
||||
pkey: 'datasource.initial_pool_size',
|
||||
pval: configuration?.initialPoolSize || 5,
|
||||
type: '',
|
||||
sort: 0
|
||||
},
|
||||
{
|
||||
pkey: 'datasource.min_pool_size',
|
||||
pval: configuration?.minPoolSize || 5,
|
||||
type: '',
|
||||
sort: 0
|
||||
},
|
||||
{
|
||||
pkey: 'datasource.max_pool_size',
|
||||
pval: configuration?.maxPoolSize || 5,
|
||||
type: '',
|
||||
sort: 0
|
||||
},
|
||||
{
|
||||
pkey: 'datasource.query_timeout',
|
||||
pval: `${configuration?.queryTimeout || 30}${t('common.second')}`,
|
||||
type: '',
|
||||
sort: 0
|
||||
querySymmetricKey().then(response => {
|
||||
getDeEngine().then(res => {
|
||||
let { id, type, configuration } = res.data
|
||||
if (configuration) {
|
||||
configuration = JSON.parse(symmetricDecrypt(configuration, response.data))
|
||||
}
|
||||
]
|
||||
nodeInfoId = id
|
||||
templateListTime.value = [
|
||||
{
|
||||
pkey: 'datasource.initial_pool_size',
|
||||
pval: configuration?.initialPoolSize || 5,
|
||||
type: '',
|
||||
sort: 0
|
||||
},
|
||||
{
|
||||
pkey: 'datasource.min_pool_size',
|
||||
pval: configuration?.minPoolSize || 5,
|
||||
type: '',
|
||||
sort: 0
|
||||
},
|
||||
{
|
||||
pkey: 'datasource.max_pool_size',
|
||||
pval: configuration?.maxPoolSize || 5,
|
||||
type: '',
|
||||
sort: 0
|
||||
},
|
||||
{
|
||||
pkey: 'datasource.query_timeout',
|
||||
pval: `${configuration?.queryTimeout || 30}${t('common.second')}`,
|
||||
type: '',
|
||||
sort: 0
|
||||
}
|
||||
]
|
||||
|
||||
templateList.value = [
|
||||
{
|
||||
pkey: t('system.engine_type'),
|
||||
pval: typeMap[type],
|
||||
type: '',
|
||||
sort: 0
|
||||
},
|
||||
{
|
||||
pkey: 'datasource.host',
|
||||
pval: configuration?.host,
|
||||
type: '',
|
||||
sort: 0
|
||||
},
|
||||
{
|
||||
pkey: 'datasource.port',
|
||||
pval: configuration?.port,
|
||||
type: '',
|
||||
sort: 0
|
||||
},
|
||||
{
|
||||
pkey: 'datasource.data_base',
|
||||
pval: configuration?.dataBase,
|
||||
type: '',
|
||||
sort: 0
|
||||
},
|
||||
{
|
||||
pkey: 'datasource.user_name',
|
||||
pval: configuration?.username,
|
||||
type: '',
|
||||
sort: 0
|
||||
},
|
||||
{
|
||||
pkey: 'datasource.extra_params',
|
||||
pval: configuration?.extraParams,
|
||||
type: '',
|
||||
sort: 0
|
||||
}
|
||||
]
|
||||
nextTick(() => {
|
||||
infoTemplate.value.init()
|
||||
infoTemplateTime.value.init()
|
||||
templateList.value = [
|
||||
{
|
||||
pkey: t('system.engine_type'),
|
||||
pval: typeMap[type],
|
||||
type: '',
|
||||
sort: 0
|
||||
},
|
||||
{
|
||||
pkey: 'datasource.host',
|
||||
pval: configuration?.host,
|
||||
type: '',
|
||||
sort: 0
|
||||
},
|
||||
{
|
||||
pkey: 'datasource.port',
|
||||
pval: configuration?.port,
|
||||
type: '',
|
||||
sort: 0
|
||||
},
|
||||
{
|
||||
pkey: 'datasource.data_base',
|
||||
pval: configuration?.dataBase,
|
||||
type: '',
|
||||
sort: 0
|
||||
},
|
||||
{
|
||||
pkey: 'datasource.user_name',
|
||||
pval: configuration?.username,
|
||||
type: '',
|
||||
sort: 0
|
||||
},
|
||||
{
|
||||
pkey: 'datasource.extra_params',
|
||||
pval: configuration?.extraParams,
|
||||
type: '',
|
||||
sort: 0
|
||||
}
|
||||
]
|
||||
nextTick(() => {
|
||||
infoTemplate.value.init()
|
||||
infoTemplateTime.value.init()
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@ -87,6 +87,8 @@ import { useEmbedded } from '@/store/modules/embedded'
|
||||
import { XpackComponent } from '@/components/plugin'
|
||||
import { iconFieldMap } from '@/components/icon-group/field-list'
|
||||
import { iconDatasourceMap } from '@/components/icon-group/datasource-list'
|
||||
import { querySymmetricKey } from '@/api/login'
|
||||
import { symmetricDecrypt } from '@/utils/encryption'
|
||||
const route = useRoute()
|
||||
const interactiveStore = interactiveStoreWithOut()
|
||||
interface Field {
|
||||
@ -464,6 +466,7 @@ const saveDsFolder = (params, successCb, finallyCb, cmd) => {
|
||||
|
||||
const dsLoading = ref(false)
|
||||
const mounted = ref(false)
|
||||
const symmetricKey = ref('')
|
||||
|
||||
const listDs = () => {
|
||||
rawDatasourceList.value = []
|
||||
@ -580,13 +583,13 @@ const handleNodeClick = data => {
|
||||
enableDataFill
|
||||
} = res.data
|
||||
if (configuration) {
|
||||
configuration = JSON.parse(Base64.decode(configuration))
|
||||
}
|
||||
if (apiConfigurationStr) {
|
||||
apiConfigurationStr = JSON.parse(Base64.decode(apiConfigurationStr))
|
||||
configuration = JSON.parse(symmetricDecrypt(configuration, symmetricKey.value))
|
||||
}
|
||||
if (paramsStr) {
|
||||
paramsStr = JSON.parse(Base64.decode(paramsStr))
|
||||
paramsStr = JSON.parse(symmetricDecrypt(paramsStr, symmetricKey.value))
|
||||
}
|
||||
if (apiConfigurationStr) {
|
||||
apiConfigurationStr = JSON.parse(symmetricDecrypt(apiConfigurationStr, symmetricKey.value))
|
||||
}
|
||||
Object.assign(nodeInfo, {
|
||||
name,
|
||||
@ -707,13 +710,13 @@ const editDatasource = (editType?: number) => {
|
||||
enableDataFill
|
||||
} = res.data
|
||||
if (configuration) {
|
||||
configuration = JSON.parse(Base64.decode(configuration))
|
||||
configuration = JSON.parse(symmetricDecrypt(configuration, symmetricKey.value))
|
||||
}
|
||||
if (paramsStr) {
|
||||
paramsStr = JSON.parse(Base64.decode(paramsStr))
|
||||
paramsStr = JSON.parse(symmetricDecrypt(paramsStr, symmetricKey.value))
|
||||
}
|
||||
if (apiConfigurationStr) {
|
||||
apiConfigurationStr = JSON.parse(Base64.decode(apiConfigurationStr))
|
||||
apiConfigurationStr = JSON.parse(symmetricDecrypt(apiConfigurationStr, symmetricKey.value))
|
||||
}
|
||||
let datasource = reactive<Node>(cloneDeep(defaultInfo))
|
||||
Object.assign(datasource, {
|
||||
@ -772,13 +775,13 @@ const handleCopy = async data => {
|
||||
lastSyncTime
|
||||
} = res.data
|
||||
if (configuration) {
|
||||
configuration = JSON.parse(Base64.decode(configuration))
|
||||
configuration = JSON.parse(symmetricDecrypt(configuration, symmetricKey.value))
|
||||
}
|
||||
if (paramsStr) {
|
||||
paramsStr = JSON.parse(Base64.decode(paramsStr))
|
||||
paramsStr = JSON.parse(symmetricDecrypt(paramsStr, symmetricKey.value))
|
||||
}
|
||||
if (apiConfigurationStr) {
|
||||
apiConfigurationStr = JSON.parse(Base64.decode(apiConfigurationStr))
|
||||
apiConfigurationStr = JSON.parse(symmetricDecrypt(apiConfigurationStr, symmetricKey.value))
|
||||
}
|
||||
let datasource = reactive<Node>(cloneDeep(defaultInfo))
|
||||
Object.assign(datasource, {
|
||||
@ -990,6 +993,9 @@ onMounted(() => {
|
||||
if (opt && opt === 'create') {
|
||||
datasourceEditor.value.init(null, null)
|
||||
}
|
||||
querySymmetricKey().then(res => {
|
||||
symmetricKey.value = res.data
|
||||
})
|
||||
})
|
||||
|
||||
const sideTreeStatus = ref(true)
|
||||
@ -1646,7 +1652,7 @@ const getMenuList = (val: boolean) => {
|
||||
</el-button>
|
||||
</BaseInfoContent>
|
||||
<BaseInfoContent
|
||||
v-if="nodeInfo.type === 'API'"
|
||||
v-if="nodeInfo.type === 'API' && nodeInfo.weight >= 7"
|
||||
v-slot="slotProps"
|
||||
:name="t('dataset.update_setting')"
|
||||
:time="(nodeInfo.lastSyncTime as string)"
|
||||
|
||||
@ -8,9 +8,11 @@ import io.dataease.rsa.manage.RsaManage;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.KeyGenerator;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
@ -176,7 +178,7 @@ public class RsaUtils {
|
||||
return pk + separator + aesKey;
|
||||
}
|
||||
|
||||
private static final String IV_KEY = "0000000000000000";
|
||||
public static final String IV_KEY = "0000000000000000";
|
||||
|
||||
private static String generateAesKey() {
|
||||
return RandomStringUtils.randomAlphanumeric(16);
|
||||
@ -200,4 +202,53 @@ public class RsaUtils {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static final String ALGORITHM = "AES";
|
||||
public static String symmetricKey = null;
|
||||
private static final int KEY_SIZE = 128;
|
||||
|
||||
|
||||
public static String generateSymmetricKey() {
|
||||
try {
|
||||
if (StringUtils.isEmpty(symmetricKey)) {
|
||||
KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM);
|
||||
keyGenerator.init(KEY_SIZE, new SecureRandom());
|
||||
SecretKey secretKey = keyGenerator.generateKey();
|
||||
symmetricKey = Base64.getEncoder().encodeToString(secretKey.getEncoded());
|
||||
}
|
||||
return symmetricKey;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static String symmetricEncrypt(String data) {
|
||||
try {
|
||||
byte[] iv = IV_KEY.getBytes(StandardCharsets.UTF_8);
|
||||
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||
SecretKeySpec secretKeySpec = new SecretKeySpec(Base64.getDecoder().decode(generateSymmetricKey()), ALGORITHM);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
|
||||
byte[] ciphertext = cipher.doFinal(data.getBytes("UTF-8"));
|
||||
return Base64.getEncoder().encodeToString(ciphertext);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static String symmetricDecrypt(String data) {
|
||||
try {
|
||||
byte[] iv = IV_KEY.getBytes(StandardCharsets.UTF_8);
|
||||
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
|
||||
SecretKeySpec secretKeySpec = new SecretKeySpec(Base64.getDecoder().decode(generateSymmetricKey()), ALGORITHM);
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
|
||||
byte[] decodedCiphertext = Base64.getDecoder().decode(data);
|
||||
byte[] decryptedText = cipher.doFinal(decodedCiphertext);
|
||||
return new String(decryptedText, "UTF-8");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,6 +24,7 @@ public class WhitelistUtils {
|
||||
"/login/localLogin",
|
||||
"/apisix/check",
|
||||
"/dekey",
|
||||
"/symmetricKey",
|
||||
"/index.html",
|
||||
"/model",
|
||||
"/xpackModel",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user