feat:【framework 框架】增加 api 加解密能力(优化代码)

This commit is contained in:
YunaiV
2025-08-16 17:20:45 +08:00
parent 2920dabb99
commit 4be6d26375
9 changed files with 112 additions and 330 deletions

View File

@@ -12,16 +12,17 @@ import {
RequestClient,
} from '@vben/request';
import { useAccessStore } from '@vben/stores';
import { createApiEncrypt } from '@vben/utils';
import { ElMessage } from 'element-plus';
import { useAuthStore } from '#/store';
import { ApiEncrypt } from '#/utils/encrypt';
import { refreshTokenApi } from './core';
const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
const tenantEnable = isTenantEnable();
const apiEncrypt = createApiEncrypt(import.meta.env);
function createRequestClient(baseURL: string, options?: RequestClientOptions) {
const client = new RequestClient({
@@ -91,9 +92,9 @@ function createRequestClient(baseURL: string, options?: RequestClientOptions) {
try {
// 加密请求数据
if (config.data) {
config.data = ApiEncrypt.encryptRequest(config.data);
config.data = apiEncrypt.encryptRequest(config.data);
// 设置加密标识头
config.headers[ApiEncrypt.getEncryptHeader()] = 'true';
config.headers[apiEncrypt.getEncryptHeader()] = 'true';
}
} catch (error) {
console.error('请求数据加密失败:', error);
@@ -108,14 +109,14 @@ function createRequestClient(baseURL: string, options?: RequestClientOptions) {
client.addResponseInterceptor({
fulfilled: (response) => {
// 检查是否需要解密响应数据
const encryptHeader = ApiEncrypt.getEncryptHeader();
const encryptHeader = apiEncrypt.getEncryptHeader();
const isEncryptResponse =
response.headers[encryptHeader] === 'true' ||
response.headers[encryptHeader.toLowerCase()] === 'true';
if (isEncryptResponse && typeof response.data === 'string') {
try {
// 解密响应数据
response.data = ApiEncrypt.decryptResponse(response.data);
response.data = apiEncrypt.decryptResponse(response.data);
} catch (error) {
console.error('响应数据解密失败:', error);
throw new Error(`响应数据解密失败: ${(error as Error).message}`);

View File

@@ -1,240 +0,0 @@
import CryptoJS from 'crypto-js';
import { JSEncrypt } from 'jsencrypt';
/**
* API 加解密工具类
* 支持 AES 和 RSA 加密算法
*/
// 从环境变量获取配置
const API_ENCRYPT_ENABLE =
import.meta.env.VITE_APP_API_ENCRYPT_ENABLE === 'true';
const API_ENCRYPT_HEADER =
import.meta.env.VITE_APP_API_ENCRYPT_HEADER || 'X-Api-Encrypt';
const API_ENCRYPT_ALGORITHM =
import.meta.env.VITE_APP_API_ENCRYPT_ALGORITHM || 'AES';
const API_ENCRYPT_REQUEST_KEY =
import.meta.env.VITE_APP_API_ENCRYPT_REQUEST_KEY || ''; // AES密钥 或 RSA公钥
const API_ENCRYPT_RESPONSE_KEY =
import.meta.env.VITE_APP_API_ENCRYPT_RESPONSE_KEY || ''; // AES密钥 或 RSA私钥
/**
* AES 加密工具类
*/
export const AES = {
/**
* AES 加密
* @param data 要加密的数据
* @param key 加密密钥
* @returns 加密后的字符串
*/
encrypt(data: string, key: string): string {
try {
if (!key) {
throw new Error('AES 加密密钥不能为空');
}
if (key.length !== 32) {
throw new Error(
`AES 加密密钥长度必须为 32 位,当前长度: ${key.length}`,
);
}
const keyUtf8 = CryptoJS.enc.Utf8.parse(key);
const encrypted = CryptoJS.AES.encrypt(data, keyUtf8, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7,
});
return encrypted.toString();
} catch (error) {
console.error('AES 加密失败:', error);
throw error;
}
},
/**
* AES 解密
* @param encryptedData 加密的数据
* @param key 解密密钥
* @returns 解密后的字符串
*/
decrypt(encryptedData: string, key: string): string {
try {
if (!key) {
throw new Error('AES 解密密钥不能为空');
}
if (key.length !== 32) {
throw new Error(
`AES 解密密钥长度必须为 32 位,当前长度: ${key.length}`,
);
}
if (!encryptedData) {
throw new Error('AES 解密数据不能为空');
}
const keyUtf8 = CryptoJS.enc.Utf8.parse(key);
const decrypted = CryptoJS.AES.decrypt(encryptedData, keyUtf8, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7,
});
const result = decrypted.toString(CryptoJS.enc.Utf8);
if (!result) {
throw new Error('AES 解密结果为空,可能是密钥错误或数据损坏');
}
return result;
} catch (error) {
console.error('AES 解密失败:', error);
throw error;
}
},
};
/**
* RSA 加密工具类
*/
export const RSA = {
/**
* RSA 加密
* @param data 要加密的数据
* @param publicKey 公钥(必需)
* @returns 加密后的字符串
*/
encrypt(data: string, publicKey: string): false | string {
try {
if (!publicKey) {
throw new Error('RSA 公钥不能为空');
}
const encryptor = new JSEncrypt();
encryptor.setPublicKey(publicKey);
const result = encryptor.encrypt(data);
if (result === false) {
throw new Error('RSA 加密失败,可能是公钥格式错误或数据过长');
}
return result;
} catch (error) {
console.error('RSA 加密失败:', error);
throw error;
}
},
/**
* RSA 解密
* @param encryptedData 加密的数据
* @param privateKey 私钥(必需)
* @returns 解密后的字符串
*/
decrypt(encryptedData: string, privateKey: string): false | string {
try {
if (!privateKey) {
throw new Error('RSA 私钥不能为空');
}
if (!encryptedData) {
throw new Error('RSA 解密数据不能为空');
}
const encryptor = new JSEncrypt();
encryptor.setPrivateKey(privateKey);
const result = encryptor.decrypt(encryptedData);
if (result === false) {
throw new Error('RSA 解密失败,可能是私钥错误或数据损坏');
}
return result;
} catch (error) {
console.error('RSA 解密失败:', error);
throw error;
}
},
};
/**
* API 加解密主类
*/
export const ApiEncrypt = {
/**
* 获取加密头名称
*/
getEncryptHeader(): string {
return API_ENCRYPT_HEADER;
},
/**
* 加密请求数据
* @param data 要加密的数据
* @returns 加密后的数据
*/
encryptRequest(data: any): string {
if (!API_ENCRYPT_ENABLE) {
return data;
}
try {
const jsonData = typeof data === 'string' ? data : JSON.stringify(data);
if (API_ENCRYPT_ALGORITHM.toUpperCase() === 'AES') {
if (!API_ENCRYPT_REQUEST_KEY) {
throw new Error('AES 请求加密密钥未配置');
}
return AES.encrypt(jsonData, API_ENCRYPT_REQUEST_KEY);
} else if (API_ENCRYPT_ALGORITHM.toUpperCase() === 'RSA') {
if (!API_ENCRYPT_REQUEST_KEY) {
throw new Error('RSA 公钥未配置');
}
const result = RSA.encrypt(jsonData, API_ENCRYPT_REQUEST_KEY);
if (result === false) {
throw new Error('RSA 加密失败');
}
return result;
} else {
throw new Error(`不支持的加密算法: ${API_ENCRYPT_ALGORITHM}`);
}
} catch (error) {
console.error('请求数据加密失败:', error);
throw error;
}
},
/**
* 解密响应数据
* @param encryptedData 加密的响应数据
* @returns 解密后的数据
*/
decryptResponse(encryptedData: string): any {
if (!API_ENCRYPT_ENABLE) {
return encryptedData;
}
try {
let decryptedData: false | string = '';
if (API_ENCRYPT_ALGORITHM.toUpperCase() === 'AES') {
if (!API_ENCRYPT_RESPONSE_KEY) {
throw new Error('AES 响应解密密钥未配置');
}
decryptedData = AES.decrypt(encryptedData, API_ENCRYPT_RESPONSE_KEY);
} else if (API_ENCRYPT_ALGORITHM.toUpperCase() === 'RSA') {
if (!API_ENCRYPT_RESPONSE_KEY) {
throw new Error('RSA 私钥未配置');
}
decryptedData = RSA.decrypt(encryptedData, API_ENCRYPT_RESPONSE_KEY);
if (decryptedData === false) {
throw new Error('RSA 解密失败');
}
} else {
throw new Error(`不支持的解密算法: ${API_ENCRYPT_ALGORITHM}`);
}
if (!decryptedData) {
throw new Error('解密结果为空');
}
// 尝试解析为 JSON如果失败则返回原字符串
try {
return JSON.parse(decryptedData);
} catch {
return decryptedData;
}
} catch (error) {
console.error('响应数据解密失败:', error);
throw error;
}
},
};