瀏覽代碼

!59 响应加密功能
Merge pull request !59 from MichelleChung/dev

疯狂的狮子Li 1 年之前
父節點
當前提交
9b4692b625
共有 6 個文件被更改,包括 45 次插入4 次删除
  1. 2 0
      .env.development
  2. 2 0
      .env.production
  3. 1 0
      src/types/env.d.ts
  4. 21 0
      src/utils/crypto.ts
  5. 1 1
      src/utils/jsencrypt.ts
  6. 18 3
      src/utils/request.ts

+ 2 - 0
.env.development

@@ -20,6 +20,8 @@ VITE_APP_PORT = 80
 
 # 接口加密传输 RSA 公钥与后端解密私钥对应 如更换需前后端一同更换
 VITE_APP_RSA_PUBLIC_KEY = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ=='
+# 接口响应解密 RSA 私钥与后端加密公钥对应 如更换需前后端一同更换
+VITE_APP_RSA_PRIVATE_KEY = 'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE='
 
 # 客户端id
 VITE_APP_CLIENT_ID = 'e5cd7e4891bf95d1d19206ce24a7b32e'

+ 2 - 0
.env.production

@@ -23,6 +23,8 @@ VITE_APP_PORT = 80
 
 # 接口加密传输 RSA 公钥与后端解密私钥对应 如更换需前后端一同更换
 VITE_APP_RSA_PUBLIC_KEY = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ=='
+# 接口响应解密 RSA 私钥与后端加密公钥对应 如更换需前后端一同更换
+VITE_APP_RSA_PRIVATE_KEY = 'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE='
 
 # 客户端id
 VITE_APP_CLIENT_ID = 'e5cd7e4891bf95d1d19206ce24a7b32e'

+ 1 - 0
src/types/env.d.ts

@@ -68,6 +68,7 @@ interface ImportMetaEnv {
   VITE_APP_POWERJOB_ADMIN: string;
   VITE_APP_ENV: string;
   VITE_APP_RSA_PUBLIC_KEY: string;
+  VITE_APP_RSA_PRIVATE_KEY: string;
   VITE_APP_CLIENT_ID: string;
   VITE_APP_WEBSOCKET: string;
 }

+ 21 - 0
src/utils/crypto.ts

@@ -30,6 +30,13 @@ export const encryptBase64 = (str: CryptoJS.lib.WordArray) => {
   return CryptoJS.enc.Base64.stringify(str);
 };
 
+/**
+ * 解密base64
+ */
+export const decryptBase64 = (str: string) => {
+  return CryptoJS.enc.Base64.parse(str);
+};
+
 /**
  * 使用密钥对数据进行加密
  * @param message
@@ -43,3 +50,17 @@ export const encryptWithAes = (message: string, aesKey: CryptoJS.lib.WordArray)
   });
   return encrypted.toString();
 };
+
+/**
+ * 使用密钥对数据进行解密
+ * @param message
+ * @param aesKey
+ * @returns {string}
+ */
+export const decryptWithAes = (message: string, aesKey: CryptoJS.lib.WordArray) => {
+  const decrypted = CryptoJS.AES.decrypt(message, aesKey, {
+    mode: CryptoJS.mode.ECB,
+    padding: CryptoJS.pad.Pkcs7
+  });
+  return decrypted.toString(CryptoJS.enc.Utf8);
+};

+ 1 - 1
src/utils/jsencrypt.ts

@@ -4,7 +4,7 @@ import JSEncrypt from 'jsencrypt';
 const publicKey = import.meta.env.VITE_APP_RSA_PUBLIC_KEY;
 
 // 前端不建议存放私钥 不建议解密数据 因为都是透明的意义不大
-const privateKey = '**********';
+const privateKey = import.meta.env.VITE_APP_RSA_PRIVATE_KEY;
 
 // 加密
 export const encrypt = (txt: string) => {

+ 18 - 3
src/utils/request.ts

@@ -8,9 +8,10 @@ import { errorCode } from '@/utils/errorCode';
 import { LoadingInstance } from 'element-plus/es/components/loading/src/loading';
 import FileSaver from 'file-saver';
 import { getLanguage } from '@/lang';
-import { encryptBase64, encryptWithAes, generateAesKey } from '@/utils/crypto';
-import { encrypt } from '@/utils/jsencrypt';
+import { encryptBase64, encryptWithAes, generateAesKey, decryptWithAes, decryptBase64 } from '@/utils/crypto';
+import { encrypt, decrypt } from '@/utils/jsencrypt';
 
+const encryptHeader = 'encrypt-key';
 let downloadLoadingInstance: LoadingInstance;
 // 是否显示重新登录
 export const isRelogin = { show: false };
@@ -78,7 +79,7 @@ service.interceptors.request.use(
     if (isEncrypt && (config.method === 'post' || config.method === 'put')) {
       // 生成一个 AES 密钥
       const aesKey = generateAesKey();
-      config.headers['encrypt-key'] = encrypt(encryptBase64(aesKey));
+      config.headers[encryptHeader] = encrypt(encryptBase64(aesKey));
       config.data = typeof config.data === 'object' ? encryptWithAes(JSON.stringify(config.data), aesKey) : encryptWithAes(config.data, aesKey);
     }
     // FormData数据去请求头Content-Type
@@ -96,6 +97,20 @@ service.interceptors.request.use(
 // 响应拦截器
 service.interceptors.response.use(
   (res: AxiosResponse) => {
+    // 加密后的 AES 秘钥
+    const keyStr = res.headers[encryptHeader];
+    // 加密
+    if (keyStr != null && keyStr != '') {
+      const data = res.data;
+      // 请求体 AES 解密
+      const base64Str = decrypt(keyStr);
+      // base64 解码 得到请求头的 AES 秘钥
+      const aesKey = decryptBase64(base64Str.toString());
+      // aesKey 解码 data
+      const decryptData = decryptWithAes(data, aesKey);
+      // 将结果 (得到的是 JSON 字符串) 转为 JSON
+      res.data = JSON.parse(decryptData);
+    }
     // 未设置状态码则默认成功状态
     const code = res.data.code || HttpStatus.SUCCESS;
     // 获取错误信息