mirror of
https://github.com/dataease/dataease.git
synced 2026-05-14 04:12:11 +08:00
feat(X-Pack): 支持 Hmac-auth
This commit is contained in:
committed by
fit2cloud-chenyw
parent
6fa2373a42
commit
b833138e27
@@ -98,6 +98,10 @@
|
||||
<key-type>java.lang.String</key-type>
|
||||
<value-type>java.lang.Object</value-type>
|
||||
</cache>
|
||||
<cache alias="de_v2_global_hmac" uses-template="common-cache">
|
||||
<key-type>java.lang.String</key-type>
|
||||
<value-type>java.lang.Object</value-type>
|
||||
</cache>
|
||||
<cache alias="de_v2_user_community_language" uses-template="common-cache">
|
||||
<key-type>java.lang.String</key-type>
|
||||
<value-type>java.lang.Object</value-type>
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
import { xpackModelApi } from '@/api/plugin'
|
||||
import { useCache } from '@/hooks/web/useCache'
|
||||
import { isNull } from '@/utils/utils'
|
||||
import { useEmbedded } from '@/store/modules/embedded'
|
||||
const { wsCache } = useCache()
|
||||
const embeddedStore = useEmbedded()
|
||||
const basePath = import.meta.env.VITE_API_BASEPATH
|
||||
const embeddedBasePath =
|
||||
basePath.startsWith('./') && basePath.length > 2 ? basePath.substring(2) : basePath
|
||||
export const PATH_URL = embeddedStore.baseUrl ? embeddedStore?.baseUrl + embeddedBasePath : basePath
|
||||
|
||||
const remoteTsUrl = PATH_URL + '/DEXPackTs.umd.js'
|
||||
const loadXpackTs = (url: string) => {
|
||||
return new Promise<void>(function (resolve, reject) {
|
||||
const scriptId = 'de-fit2cloud-script-xpack-ts-id'
|
||||
let dom = document.getElementById(scriptId)
|
||||
if (dom) {
|
||||
dom.parentElement?.removeChild(dom)
|
||||
dom = null
|
||||
}
|
||||
const script = document.createElement('script')
|
||||
|
||||
script.id = scriptId
|
||||
script.onload = function () {
|
||||
return resolve()
|
||||
}
|
||||
script.onerror = function () {
|
||||
return reject(new Error('Load script from '.concat(url, ' failed')))
|
||||
}
|
||||
script.src = url
|
||||
const head = document.head || document.getElementsByTagName('head')[0]
|
||||
;(document.body || head).appendChild(script)
|
||||
})
|
||||
}
|
||||
|
||||
export const importXpackTool = async (methodName: string) => {
|
||||
const jsname = 'L3Rvb2xzL0htYWNUb29s'
|
||||
const key = 'xpack-model-distributed'
|
||||
let distributed = false
|
||||
if (wsCache.get(key) === null) {
|
||||
const res = await xpackModelApi()
|
||||
const resData = isNull(res.data) ? 'null' : res.data
|
||||
wsCache.set('xpack-model-distributed', resData)
|
||||
distributed = res.data
|
||||
} else {
|
||||
distributed = wsCache.get(key)
|
||||
}
|
||||
distributed = true
|
||||
if (isNull(distributed) || !distributed) {
|
||||
return null
|
||||
}
|
||||
if (window['DEXPackTs']) {
|
||||
const xpack = await window['DEXPackTs'].mapping[jsname]
|
||||
return xpack[methodName]
|
||||
} else {
|
||||
if (!window['de_hmac_promise']) {
|
||||
window['de_hmac_promise'] = null
|
||||
}
|
||||
if (!window['de_hmac_promise']) {
|
||||
window['de_hmac_promise'] = loadXpackTs(remoteTsUrl)
|
||||
.then(() => {
|
||||
return window['DEXPackTs']
|
||||
})
|
||||
.catch((error: any) => {
|
||||
window['__de_xpack_loading__'] = null
|
||||
throw error
|
||||
})
|
||||
}
|
||||
await window['de_hmac_promise']
|
||||
const xpack = await window['DEXPackTs'].mapping[jsname]
|
||||
return xpack[methodName]
|
||||
}
|
||||
}
|
||||
18
core/core-frontend/src/config/axios/hmac.ts
Normal file
18
core/core-frontend/src/config/axios/hmac.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { importXpackTool } from '@/components/plugin/src/ImportXpackTool'
|
||||
|
||||
const hmac_white_list = ['/xpackModel']
|
||||
export const securityConfig = async (config: any, requestPath: string) => {
|
||||
if (hmac_white_list.some(item => requestPath.includes(item))) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
const method = await importXpackTool('securityConfig')
|
||||
if (!method) {
|
||||
return
|
||||
}
|
||||
return method(config, requestPath)
|
||||
} catch (error) {
|
||||
console.error('Failed to load securityConfig method:', error)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import { configHandler } from './refresh'
|
||||
import { isMobile, getLocale } from '@/utils/utils'
|
||||
import { useRequestStoreWithOut } from '@/store/modules/request'
|
||||
import { clearCache } from '@/utils/cacheUtil'
|
||||
import { securityConfig } from './hmac'
|
||||
|
||||
type AxiosErrorWidthLoading<T> = T & {
|
||||
config: {
|
||||
@@ -100,6 +101,7 @@ service.interceptors.request.use(
|
||||
if (config instanceof Promise) {
|
||||
config = await config
|
||||
}
|
||||
await securityConfig(config, service.getUri(config))
|
||||
if (
|
||||
config.method === 'post' &&
|
||||
(config.headers as AxiosRequestHeaders)['Content-Type'] ===
|
||||
|
||||
@@ -4814,6 +4814,10 @@ export default {
|
||||
security: {
|
||||
title: 'Security Settings'
|
||||
},
|
||||
setting_hmac: {
|
||||
title: 'HMAC Settings',
|
||||
enable: 'Enable HMAC Authentication'
|
||||
},
|
||||
setting_mfa: {
|
||||
title: 'MFA Settings',
|
||||
status: 'Global MFA Authentication Enabled',
|
||||
|
||||
@@ -4670,6 +4670,10 @@ export default {
|
||||
security: {
|
||||
title: '安全設置'
|
||||
},
|
||||
setting_hmac: {
|
||||
title: 'HMAC 設定',
|
||||
enable: '啟用 HMAC 認證'
|
||||
},
|
||||
setting_mfa: {
|
||||
title: 'MFA 設置',
|
||||
status: '全局啟用 MFA 認證',
|
||||
|
||||
@@ -4679,6 +4679,10 @@ export default {
|
||||
security: {
|
||||
title: '安全设置'
|
||||
},
|
||||
setting_hmac: {
|
||||
title: 'HMAC 设置',
|
||||
enable: '启用 HMAC 认证'
|
||||
},
|
||||
setting_mfa: {
|
||||
title: 'MFA 设置',
|
||||
status: '全局启用 MFA 认证',
|
||||
|
||||
@@ -41,4 +41,21 @@ public interface PerSettingApi {
|
||||
@Operation(summary = "查询MFA状态")
|
||||
@GetMapping("/mfaStatus")
|
||||
Integer mfaStatus();
|
||||
|
||||
|
||||
@Operation(summary = "查询Hmac设置")
|
||||
@GetMapping("/hmac/query")
|
||||
List<PerSettingItemVO> hmacSetting();
|
||||
|
||||
@Operation(summary = "保存Hmac设置")
|
||||
@PostMapping("/hmac/save")
|
||||
void saveHmac(@RequestBody List<PerSettingItemVO> settings);
|
||||
|
||||
@Hidden
|
||||
@GetMapping("/hmac/info")
|
||||
String hmacInfo();
|
||||
|
||||
@Hidden
|
||||
@PostMapping("/hmac/refresh")
|
||||
String refreshHmacSecret();
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ public class CacheConstant {
|
||||
public static final String RSA_CACHE = "de_v2_rsa";
|
||||
public static final String PER_MENU_ID_CACHE = "de_v2_per_menu_id";
|
||||
public static final String GLOBAL_MFA_CACHE = "de_v2_global_mfa";
|
||||
public static final String GLOBAL_HMAC_CACHE = "de_v2_global_hmac";
|
||||
}
|
||||
|
||||
public static class LicenseCacheConstant {
|
||||
|
||||
@@ -9,6 +9,8 @@ import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
public class AesUtils {
|
||||
@@ -62,4 +64,31 @@ public class AesUtils {
|
||||
public static Object aesDecrypt(Object o) {
|
||||
return o == null ? null : aesDecrypt(o.toString(), "www.fit2cloud.co", "1234567890123456");
|
||||
}
|
||||
|
||||
public static String aesEncryptWithIv(String src, String secretKey) {
|
||||
if (StringUtils.isBlank(secretKey)) {
|
||||
throw new RuntimeException("secretKey is empty");
|
||||
}
|
||||
try {
|
||||
// 生成随机IV
|
||||
byte[] iv = new byte[16];
|
||||
new SecureRandom().nextBytes(iv);
|
||||
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
||||
|
||||
byte[] raw = secretKey.getBytes(UTF_8);
|
||||
SecretKeySpec secretKeySpec = new SecretKeySpec(raw, "AES");
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivSpec);
|
||||
byte[] encrypted = cipher.doFinal(src.getBytes(UTF_8));
|
||||
|
||||
// 将IV拼接到密文前面
|
||||
byte[] ivAndCipher = new byte[iv.length + encrypted.length];
|
||||
System.arraycopy(iv, 0, ivAndCipher, 0, iv.length);
|
||||
System.arraycopy(encrypted, 0, ivAndCipher, iv.length, encrypted.length);
|
||||
|
||||
return Base64.encodeBase64String(ivAndCipher);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("AES encrypt error:", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ public class WhitelistUtils {
|
||||
"/embedded/initIframe",
|
||||
"/sysParameter/i18nOptions",
|
||||
"/login/modifyInvalidPwd",
|
||||
"/perSetting/hmac/info",
|
||||
"/");
|
||||
|
||||
public static boolean match(String requestURI) {
|
||||
|
||||
Reference in New Issue
Block a user