diff --git a/src/config/axios/service.ts b/src/config/axios/service.ts index 618f14a9940d86d3cb3fa1ec415666e3c6e6dd76..77a535786ea5568db688221fab57e9ec6c93f860 100644 --- a/src/config/axios/service.ts +++ b/src/config/axios/service.ts @@ -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) => { let { data } = response const config = response.config + if(config.headers!.ENCPARAMTER === 'true'){ + data = securityUtils.gatewayResponse(response); + } if (!data) { // 返回“[HTTP]请求没有返回值”; throw new Error() diff --git a/src/utils/securityUtils.js b/src/utils/securityUtils.js new file mode 100755 index 0000000000000000000000000000000000000000..d366ca32e4dcdca986a74f7a8b9487e25369ff61 --- /dev/null +++ b/src/utils/securityUtils.js @@ -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 +}