添加前后端消息体加解密,responseBody requestBody,for get post put

pull/656/head
让无线电飞BG8GLR 2025-01-10 20:16:50 +08:00
parent e9950929de
commit 1d05891b55
2 changed files with 340 additions and 0 deletions

View File

@ -8,6 +8,7 @@ import errorCode from './errorCode'
import { resetRouter } from '@/router'
import { deleteUserCache } from '@/hooks/web/useCache'
import securityUtils from "@/utils/securityUtils";
const tenantEnable = import.meta.env.VITE_APP_TENANT_ENABLE
const { result_code, base_url, request_timeout } = config
@ -71,6 +72,9 @@ service.interceptors.request.use(
}
}
}
if(method === 'POST' || method === 'GET' || method === 'PUT'){
return securityUtils.gatewayRequest(config);
}
return config
},
(error: AxiosError) => {
@ -85,6 +89,9 @@ service.interceptors.response.use(
async (response: AxiosResponse<any>) => {
let { data } = response
const config = response.config
if(config.headers!.ENCPARAMTER === 'true'){
data = securityUtils.gatewayResponse(response);
}
if (!data) {
// 返回“[HTTP]请求没有返回值”;
throw new Error()

333
src/utils/securityUtils.js Executable file
View File

@ -0,0 +1,333 @@
import crypto from "crypto";
import {JSEncrypt} from "jsencrypt";
import CryptoJS from 'crypto-js'
/** 全局变量配置-start **/
const _publicKey = 'LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS1NSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXkzREU2MEpCUUNCbG8xay9qRWlVcCtjeVc1OGYxMStML0xFcE1HZ0gwbzFzN1BjdzFpZG9WSm5OSUw5K1BMSnBoN2JFNUFzdWYycDZTWDZOU294NjIrMURaS0s2eUhNcFc2aEZYTlJmNG1BTEJQM0tXWlJHQjI2cU1nOXJ5Wnl3ejJFZzNlVGhMU1N0YjBJREtVWjJZbXp2N0tlSWE2K3pxaDFXeTcrcTlOcXIxQU9aU01vdjdGS3VHeTI4M21rSEVhckRxMlV6bFMzZnpsSk12THM4MG9qNWVtbTVWNE03ZmozUzZpNnVlajYybVlBZDFZT1NnZXVtRkpyblc3ZEhyaUhvazNIMEJ3NDI1ZExmREk3TkIzRXFEbU1xVytvYWFCK2U4aUMwbFFLU3hTeHVRS2Y0K2M3TWFtRmZOTjlrWmJpeUhyZUswM09iTkljbnlhMTBxd0lEQVFBQi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQ=='
// url白名单设置 暂无使用
const whiteList = [
"/tick/auth/login",
"/k",
"/cn",
]
/** 全局变量配置-end **/
export default {
/**
* 读取信息
*/
get(key) {
return sessionStorage.getItem(key)
},
/**
* 添加信息
*/
set(key, value) {
sessionStorage.setItem(key, value)
},
/**
* gateway网关验证信息处理(请求头)
*/
gatewayRequest(request) {
let key = true;
whiteList.find(function (value) {
if (value === request.url) {
key = false;
}
});
// 对非白名单请求进行处理
if (key) {
request.headers.ENCPARAMTER = 'true'; //提示后端要加解密
// 请求体数据
let frontSecKEY = this.get("frontSecKEY")
if(!frontSecKEY){ //不存在,则生成
frontSecKEY = this.generateString(16);
this.set("frontSecKEY",frontSecKEY);
}
//将临时生成的密钥发后端
let _pk = CryptoJS.enc.Utf8.stringify(CryptoJS.enc.Base64.parse(_publicKey));
request.headers.frontSecKEY = this.rsaEncrypt(frontSecKEY, _pk); //base64转_publicKey回utf8来
// 使用此密钥将请求整体加密
if(request.data){
let _data = JSON.stringify(request.data);
_data = this.encryptAES(_data, frontSecKEY);
request.data =_data;
}
}
return request;
},
/**
* gateway网关验证信息处理(响应头)
*/
gatewayResponse(response) {
let key = true;
// 放置业务逻辑代码
// response是服务器端返回来的数据信息与Promise获得数据一致
let data = response.data
// config包含请求信息
let config = response.config
// 获取当前请求的url
let url = config.url
whiteList.find(function (value) {
if (value === url) {
key = false;
}
});
// 对非白名单数据进行整体解密处理
if (key) {
// 获取加密密钥,并传入解密组件进行解密
let frontSecKEY = this.get("frontSecKEY")
// data = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(data))
data = this.decryptAES(data,frontSecKEY);
if (data != null && data !== "") {
data = JSON.parse(data);
}else {
data = new Promise(() => {});
}
}
// 判断 data 是否为对象
if (typeof data === 'object' && data !== null) {
// 判断 data 是否匹配特定格式
if (
Object.prototype.hasOwnProperty.call(data, 'msg') &&
Object.prototype.hasOwnProperty.call(data, 'code') &&
typeof data.msg === 'string' &&
typeof data.code === 'number'
) {
// 数据匹配特定格式
if (data.code === 401) {
sessionStorage.clear()
}
return data;
}
}
return data;
},
/**
* 用于生成aes密钥
*
*/
generateString(length) {
var result = '';
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var charactersLength = characters.length;
for (var i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
result = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(result))
return result;
},
/**
* 用于网关请求 /cn 请求前的处理
*
* @returns {{ck: (string|null), k: string}}
*/
secureConnectionPrepare() {
const publicKey = this.get("publicKey")
const publicKeyMd5 = this.strToMd5(publicKey)
let clientPublicKey = this.communication()
clientPublicKey = this.rsaEncrypt(clientPublicKey, publicKey)
return {
"k": publicKeyMd5,
"ck": clientPublicKey,
};
},
/**
* 用于网关请求 /cn 请求后的处理
*/
secureConnection(data) {
const privateKey = this.get("privateKey")
data = this.rsaDecrypt(data, privateKey)
data = JSON.parse(data)
this.set("secretKey", data.secretKey)
this.set("sessionId", data.sessionId)
this.set("serverPublicKey", data.publicKey)
},
//************************************网关通信-end
/**
* 生成公钥私钥对保存本地并返回公钥
*
* @returns {string}
*/
communication() {
const keys = this.rsaGenerateKey();
const publicKey = keys.publicKey;
const privateKey = keys.privateKey;
this.set("privateKey", privateKey)
return publicKey
},
//************************************公用加密方法-start
/**
* 将字符串取值MD5
*
* @param string 字符串对象
* @returns {string} 字符串md5数值
*/
strToMd5(string) {
// 规定使用哈希算法中的MD5算法
const hash = crypto.createHash('md5');
// 可任意多次调用update(),效果相当于多个字符串相加
hash.update(string);
// hash.digest('hex')表示输出的格式为16进制
return hash.digest('hex');
},
//************************************公用加密方法-end
//************************************AES对称加解密-start
/**
* AES对称加密数据
*
* @param {String} data 待加密的数据
* @param {String} base64Key base64格式的密钥
* @returns {String} 加密后的数据
*/
encryptAES(data, base64Key) {
let encryptedBytes = null;
if (data != null && base64Key != null) {
const key = CryptoJS.enc.Base64.parse(base64Key);
encryptedBytes = CryptoJS.AES.encrypt(data, key, {mode: CryptoJS.mode.ECB});
encryptedBytes = encryptedBytes.toString();
}
return encryptedBytes;
},
/**
* AES对称-解密数据
*
* @param {String} data 待解密的数据
* @param {String} base64Key base64格式的密钥
* @returns {String} 解密后的数据
*/
decryptAES(data, base64Key) {
let decryptData = null;
if (data != null && base64Key != null) {
const key = CryptoJS.enc.Base64.parse(base64Key)
const decryptBytes = CryptoJS.AES.decrypt(data, key, {mode: CryptoJS.mode.ECB})
decryptData = CryptoJS.enc.Utf8.stringify(decryptBytes);
}
return decryptData
},
//************************************AES对称加解密-end
//************************************RSA非对称加解密-start
/**
* 非对称加解密-生成公钥与私钥
*/
rsaGenerateKey() {
let keys = {
"publicKey": "",
"privateKey": "",
}
// 创建 JSEncrypt 实例
const encrypt = new JSEncrypt();
// 生成密钥对(公钥和私钥)
const keyPair = encrypt.getKey();
// 获取公钥和私钥
keys.publicKey = keyPair.getPublicBaseKeyB64();
keys.privateKey = keyPair.getPrivateBaseKeyB64();
return keys
},
/**
* 非对称加解密-公钥加密信息(分段加密)
*
* @param string 内容
* @param publicKey 非对称私钥
* @returns {string | null}
*/
rsaEncrypt(string, publicKey) {
let encryptData = null;
if (string != null && publicKey != null) {
const encryptor = new JSEncrypt({default_key_size:2048});
encryptor.setPublicKey(publicKey);
encryptData = encryptor.encrypt(string);
}
return encryptData;
},
/**
* 非对称加解密-私钥解密信息(分段解密)
*
* @param string 加密内容
* @param privateKey 非对称私钥
* @returns {string | null}
*/
rsaDecrypt(string, privateKey) {
let decryptData = null;
if (string != null && privateKey != null) {
const encryptor = new JSEncrypt();
encryptor.setPrivateKey(privateKey);
// 根据私钥的长度确定块大小,一般为私钥长度减去一些填充长度
const blockSize = 172;
const encryptedLength = string.length;
let decryptedBlocks = [];
// 拆分加密文本为块并逐个解密
for (let i = 0; i < encryptedLength; i += blockSize) {
const block = string.substr(i, blockSize);
const decryptedBlock = encryptor.decrypt(block);
decryptedBlocks.push(decryptedBlock);
}
decryptData = decryptedBlocks.join('')
}
// 将解密的块合并为单个字符串
return decryptData;
},
//************************************RSA非对称加解密-end
}