|
|
@@ -0,0 +1,290 @@
|
|
|
+import { GM2Utils, GM3Utils, gmDecrypt, gmEncrypt } from '@vben/utils';
|
|
|
+
|
|
|
+/**
|
|
|
+ * 国密加密API使用示例
|
|
|
+ * 展示如何在API中使用国密SM4加密功能
|
|
|
+ *
|
|
|
+ * 注意:请求拦截器已自动集成SM4解密,默认会解密所有字符串响应
|
|
|
+ * 只有设置 skipDecrypt: true 的接口才会跳过解密
|
|
|
+ */
|
|
|
+import { requestClient } from '#/api/request';
|
|
|
+
|
|
|
+export namespace AuthGMApi {
|
|
|
+ /** 登录接口参数 */
|
|
|
+ export interface LoginParams {
|
|
|
+ account: string;
|
|
|
+ pwd: string;
|
|
|
+ code: string;
|
|
|
+ uuid: string;
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 登录接口返回值 */
|
|
|
+ export interface LoginResult {
|
|
|
+ account: string;
|
|
|
+ accountid: string;
|
|
|
+ bm: null | string;
|
|
|
+ bmid: number;
|
|
|
+ grouplist: string;
|
|
|
+ nickname: string;
|
|
|
+ popedom: string;
|
|
|
+ timeout: number;
|
|
|
+ token: string;
|
|
|
+ workerid: string;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 登录API(国密版本)
|
|
|
+ * 后端返回SM4加密的登录结果,拦截器会自动解密
|
|
|
+ */
|
|
|
+export async function loginWithGMApi(data: AuthGMApi.LoginParams) {
|
|
|
+ return requestClient.post<AuthGMApi.LoginResult>('/api/sys/login', data, {
|
|
|
+ responseReturn: 'body', // 默认会自动使用SM4解密
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 获取用户信息(国密版本)
|
|
|
+ * 敏感用户信息使用SM4加密传输
|
|
|
+ */
|
|
|
+export async function getUserInfoGMApi(userId: string) {
|
|
|
+ return requestClient.get(`/api/user/info/${userId}`, {
|
|
|
+ responseReturn: 'data', // 默认会使用SM4解密
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 发送加密数据到后端
|
|
|
+ * 演示如何在发送前对敏感数据进行加密
|
|
|
+ */
|
|
|
+export async function sendEncryptedDataApi(sensitiveData: any) {
|
|
|
+ // 使用SM4加密敏感数据(异步)
|
|
|
+ const encryptedData = await gmEncrypt(JSON.stringify(sensitiveData));
|
|
|
+
|
|
|
+ return requestClient.post(
|
|
|
+ '/api/secure/data',
|
|
|
+ {
|
|
|
+ encryptedPayload: encryptedData,
|
|
|
+ timestamp: Date.now(),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ responseReturn: 'data', // 响应会自动解密
|
|
|
+ },
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 文件上传API
|
|
|
+ * 文件数据不需要解密,跳过解密处理
|
|
|
+ */
|
|
|
+export async function uploadFileGMApi(formData: FormData) {
|
|
|
+ return requestClient.post('/api/file/upload', formData, {
|
|
|
+ skipDecrypt: true, // 跳过解密
|
|
|
+ headers: {
|
|
|
+ 'Content-Type': 'multipart/form-data',
|
|
|
+ },
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 使用SM2进行密钥交换的示例
|
|
|
+ * 演示如何在前端生成密钥对并与后端交换
|
|
|
+ */
|
|
|
+export async function exchangeKeysWithSM2Api() {
|
|
|
+ // 生成SM2密钥对(异步)
|
|
|
+ const keyPair = await GM2Utils.generateKeyPair();
|
|
|
+
|
|
|
+ // 发送公钥到后端
|
|
|
+ const response = await requestClient.post('/api/crypto/exchange-keys', {
|
|
|
+ publicKey: keyPair.publicKey,
|
|
|
+ algorithm: 'SM2',
|
|
|
+ });
|
|
|
+
|
|
|
+ return {
|
|
|
+ localKeyPair: keyPair,
|
|
|
+ serverResponse: response,
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 使用SM3进行数据完整性校验的示例
|
|
|
+ */
|
|
|
+export async function verifyDataIntegrityApi(data: any) {
|
|
|
+ // 计算数据的SM3哈希值(异步)
|
|
|
+ const dataString = JSON.stringify(data);
|
|
|
+ const hash = await GM3Utils.digest(dataString);
|
|
|
+
|
|
|
+ // 发送数据和哈希值到后端进行校验
|
|
|
+ return requestClient.post('/api/data/verify', {
|
|
|
+ data,
|
|
|
+ hash,
|
|
|
+ algorithm: 'SM3',
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 混合加密示例
|
|
|
+ * 使用SM2交换SM4密钥,然后用SM4加密大量数据
|
|
|
+ */
|
|
|
+export namespace HybridCryptoApi {
|
|
|
+ let sm4Key: null | string = null;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 初始化混合加密,交换SM4密钥
|
|
|
+ */
|
|
|
+ export async function initializeHybridCrypto() {
|
|
|
+ // 生成SM2密钥对(异步)
|
|
|
+ const sm2KeyPair = await GM2Utils.generateKeyPair();
|
|
|
+
|
|
|
+ // 获取服务器的SM2公钥
|
|
|
+ const serverKeyResponse = await requestClient.get(
|
|
|
+ '/api/crypto/server-public-key',
|
|
|
+ );
|
|
|
+ const serverPublicKey = serverKeyResponse.publicKey;
|
|
|
+
|
|
|
+ // 生成随机SM4密钥
|
|
|
+ const generatedSm4Key = Math.random().toString(36).slice(2, 18); // 16字符密钥
|
|
|
+
|
|
|
+ // 使用服务器公钥加密SM4密钥(异步)
|
|
|
+ const encryptedSM4Key = await GM2Utils.encrypt(
|
|
|
+ generatedSm4Key,
|
|
|
+ serverPublicKey,
|
|
|
+ );
|
|
|
+
|
|
|
+ // 发送加密的SM4密钥到服务器
|
|
|
+ await requestClient.post('/api/crypto/exchange-sm4-key', {
|
|
|
+ encryptedKey: encryptedSM4Key,
|
|
|
+ clientPublicKey: sm2KeyPair.publicKey,
|
|
|
+ });
|
|
|
+
|
|
|
+ // 保存SM4密钥用于后续加密
|
|
|
+ sm4Key = generatedSm4Key;
|
|
|
+
|
|
|
+ return generatedSm4Key;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 使用混合加密发送大量数据
|
|
|
+ */
|
|
|
+ export async function sendLargeDataWithHybridCrypto(largeData: any) {
|
|
|
+ if (!sm4Key) {
|
|
|
+ await initializeHybridCrypto();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 使用SM4加密大量数据(异步)
|
|
|
+ const encryptedData = await gmEncrypt(JSON.stringify(largeData));
|
|
|
+
|
|
|
+ return requestClient.post('/api/data/large', {
|
|
|
+ encryptedData,
|
|
|
+ encryptionMethod: 'hybrid-sm2-sm4',
|
|
|
+ });
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 批量加密API工具类
|
|
|
+ */
|
|
|
+export const GMCryptoApiUtils = {
|
|
|
+ /**
|
|
|
+ * 批量加密多个字段
|
|
|
+ */
|
|
|
+ encryptFields(data: Record<string, any>, fieldsToEncrypt: string[]) {
|
|
|
+ const result = { ...data };
|
|
|
+
|
|
|
+ fieldsToEncrypt.forEach((field) => {
|
|
|
+ if (result[field] !== undefined) {
|
|
|
+ result[field] = gmEncrypt(String(result[field]));
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ return result;
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 批量解密多个字段
|
|
|
+ */
|
|
|
+ decryptFields(data: Record<string, any>, fieldsToDecrypt: string[]) {
|
|
|
+ const result = { ...data };
|
|
|
+
|
|
|
+ fieldsToDecrypt.forEach((field) => {
|
|
|
+ if (result[field] !== undefined) {
|
|
|
+ try {
|
|
|
+ result[field] = gmDecrypt(result[field]);
|
|
|
+ } catch (error) {
|
|
|
+ console.error(`解密字段 ${field} 失败:`, error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ return result;
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 安全API调用,自动处理敏感字段加密
|
|
|
+ */
|
|
|
+ async secureApiCall<T = any>(
|
|
|
+ method: 'DELETE' | 'GET' | 'POST' | 'PUT',
|
|
|
+ url: string,
|
|
|
+ data?: any,
|
|
|
+ sensitiveFields: string[] = [],
|
|
|
+ ): Promise<T> {
|
|
|
+ let processedData = data;
|
|
|
+
|
|
|
+ // 如果有敏感字段,进行加密
|
|
|
+ if (data && sensitiveFields.length > 0) {
|
|
|
+ processedData = this.encryptFields(data, sensitiveFields);
|
|
|
+ }
|
|
|
+
|
|
|
+ const config = {
|
|
|
+ responseReturn: 'data' as const,
|
|
|
+ // 响应会自动使用SM4解密
|
|
|
+ };
|
|
|
+
|
|
|
+ switch (method) {
|
|
|
+ case 'DELETE': {
|
|
|
+ return requestClient.delete<T>(url, {
|
|
|
+ ...config,
|
|
|
+ params: processedData,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ case 'GET': {
|
|
|
+ return requestClient.get<T>(url, { ...config, params: processedData });
|
|
|
+ }
|
|
|
+ case 'POST': {
|
|
|
+ return requestClient.post<T>(url, processedData, config);
|
|
|
+ }
|
|
|
+ case 'PUT': {
|
|
|
+ return requestClient.put<T>(url, processedData, config);
|
|
|
+ }
|
|
|
+ default: {
|
|
|
+ throw new Error(`Unsupported method: ${method}`);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+};
|
|
|
+
|
|
|
+// 使用示例:
|
|
|
+//
|
|
|
+// // 基本登录(自动解密)
|
|
|
+// const loginResult = await loginWithGMApi({
|
|
|
+// account: 'admin',
|
|
|
+// pwd: '123456',
|
|
|
+// code: '1234',
|
|
|
+// uuid: 'test-uuid'
|
|
|
+// });
|
|
|
+//
|
|
|
+// // 发送加密数据
|
|
|
+// const sensitiveData = { creditCard: '1234-5678-9012-3456', ssn: '123-45-6789' };
|
|
|
+// await sendEncryptedDataApi(sensitiveData);
|
|
|
+//
|
|
|
+// // 混合加密
|
|
|
+// await HybridCryptoApi.initializeHybridCrypto();
|
|
|
+// await HybridCryptoApi.sendLargeDataWithHybridCrypto(bigDataObject);
|
|
|
+//
|
|
|
+// // 安全API调用
|
|
|
+// const result = await GMCryptoApiUtils.secureApiCall('POST', '/api/user/update', {
|
|
|
+// id: 123,
|
|
|
+// name: 'John',
|
|
|
+// password: 'secret123',
|
|
|
+// email: 'john@example.com'
|
|
|
+// }, ['password', 'email']); // 只加密password和email字段
|