Pre Merge pull request !767 from 让无线电飞BG8GLR/master

pull/767/MERGE
让无线电飞BG8GLR 2025-08-16 05:27:38 +00:00 committed by Gitee
commit 6ec4489883
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
3 changed files with 361 additions and 0 deletions

5
.env
View File

@ -23,3 +23,8 @@ VITE_APP_BAIDU_CODE = a1ff8825baa73c3a78eb96aa40325abc
VITE_APP_DEFAULT_LOGIN_TENANT = 芋道源码
VITE_APP_DEFAULT_LOGIN_USERNAME = admin
VITE_APP_DEFAULT_LOGIN_PASSWORD = admin123
# 前后端加密开关
VITE_APP_ENCRYPT_ENABLE=true
# 前后端加密公钥
VITE_APP_ENCRYPT_PUBLIC_KEY='TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUFtb2VPOHhUMDNMWXBkaGdrUU1SZQp3ZkFKUzY0WFl3UTlUWWhiY0JXTklUaGZWaWpreXFIYjFIaUVXalVxek1XZTlERzF5dzcyUTVNVEY5T3YwRTBzClFVT0J3VERpVzZTRlJ6K0UvTFRXYkRPR3VjY0Z6WXBPUTYwMGpOdnJPSUlWNmsxTnVDTHhWVFRSNjFBZ1pkWnEKNnNQcUdadmxoRjQ2WnRlUWtoWjRwcURoOWNyVTBCeGoxWHFnQ2pFWmJ4V0VsenJSR3AxRGxaYjk2QVNFWElGOApnMWZsYitBTUliK3hyU0VVS3YzN2RYY0M0ZDdaNVlhY0EwUHBoWlhSamhWaStDR2Y0bEdCNS9QRnVLdnVwSE5SCmVQemk3ZlhKcXBxUTRUUldvUDBXMWtyZmE3QW9Ed2RDbTNOVWNIQW4zLzI1Z2t5ajhkOWFzaFhzOU92dEJtNGQKcHdJREFRQUI='

View File

@ -15,6 +15,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
@ -83,6 +84,16 @@ service.interceptors.request.use(
}
}
}
const enc = import.meta.env.VITE_APP_ENCRYPT_ENABLE
// 前后端加密开关
// 仅对以下方法进行加密
if(enc && enc === 'true'){
if(method === 'POST' || method === 'GET' || method === 'PUT'){
return securityUtils.gatewayRequest(config);
}
}
return config
},
(error: AxiosError) => {
@ -97,6 +108,10 @@ 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()

341
src/utils/securityUtils.js Normal file
View File

@ -0,0 +1,341 @@
/**
* 前后端加密解密工具类
* 1. 前端生成16位随机密码通过rsa公钥加密发送给后端
* 2. 后端将返回数据使用随机密码加密数据返回前端前端使用随机密码进行解密
* 3. 仅对get put post请求进行加密
* 4. .env中配置公钥
* 5. .env中配置开关开启加密功能
*/
import crypto from "crypto";
import {JSEncrypt} from "jsencrypt";
import CryptoJS from 'crypto-js'
/** 全局变量配置-start **/
const _publicKey = import.meta.env.VITE_APP_ENCRYPT_PUBLIC_KEY; // 公钥
// 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
}