后端部分
使用nodejs的express框架搭建
utils/AES.js 编写AES的加解密函数
const crypto = require('crypto');
const secretKey = '1234567890123456'; // 16 字节的密钥,必须为 16/24/32 字节
const iv = crypto.randomBytes(16); // 生成随机初始向量
// AES 加密函数
function AES_encrypt(text) {
const cipher = crypto.createCipheriv('aes-128-cbc', Buffer.from(secretKey), iv);
let encrypted = cipher.update(text, 'utf8', 'base64');
encrypted += cipher.final('base64');
return {
iv: iv.toString('hex'),
content: encrypted // 返回 Base64 编码的加密内容
};
}
// AES 解密函数
function AES_decrypt(encryptedText, ivHex) {
console.log(encryptedText, ivHex);
const decipher = crypto.createDecipheriv('aes-128-cbc', Buffer.from(secretKey), Buffer.from(ivHex, 'hex'));
// let decrypted = decipher.update(encryptedText, 'hex', 'utf8');
let decrypted = decipher.update(Buffer.from(encryptedText, 'base64'), 'binary', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}
// //测试加密
// const encryptedText = { account: '111222', password: 'booway1234' };
// const encrypted = AES_encrypt(JSON.stringify(encryptedText));
// console.log(encrypted); // { iv: 'a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6', content: 'a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6' }
// console.log(JSON.stringify(encrypted)); // {"iv":"a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6","content":"a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"}
// //测试解密
// const decryptedText = AES_decrypt(encrypted.content, encrypted.iv);
// console.log(JSON.parse(decryptedText)); // { account: '111222', password: 'booway1234' }
// console.log(decryptedText); // {"account":"111222","password":"booway1234"}
exports.AES_encrypt = AES_encrypt;
exports.AES_decrypt = AES_decrypt;
解密中间件 middleware/AES_decrypt.js
const { AES_decrypt } = require('../utils/AES')
const decryptFn = (req, res, next) => {
console.log(req.body.content, req.body.iv)
if (req.body && req.body.content) {
try {
const decryptedData = AES_decrypt(req.body.content, req.body.iv);
req.body = JSON.parse(decryptedData); // 将解密后的数据赋给 req.body
console.log('解密后的请求数据:', req.body);
} catch (error) {
console.error('解密请求数据时出错:', error);
return res.status(400).send('Invalid content data.');
}
}
next(); // 继续处理请求
}
module.exports = decryptFn;
加密中间件 middleware/AES_encrypt.js
const { AES_encrypt } = require('../utils/AES');
const secretFn = (req, res, next) => {
const originalSend = res.send;
// 包装 res.send 方法
res.send = function (data) {
if (typeof data === 'object' && data !== null) {
// 将data转换为字符串
const dataStr = JSON.stringify(data);
// 对响应数据进行加密
const encryptedResponse = AES_encrypt(dataStr);
// console.log('加密前的数据:', dataStr);
// console.log('加密后的数据:', encryptedResponse);
// console.log("加密后的数据类型:" + typeof encryptedResponse)
// 继续用原始 send 方法发送加密后的数据
// 加密后的数据类型是对象,这里需要转换为字符串,防止循环调用sned方法
originalSend.call(this, JSON.stringify(encryptedResponse));
}
};
next();
}
module.exports = secretFn;
前端部分
vue3环境 utils/aes.js 封装AES加解密函数
import CryptoJS from 'crypto-js';
// 定义密钥,确保这个密钥安全且不被泄露
const secretKey = '1234567890123456'; // 16 字节的密钥
// AES 加密函数
export function AES_encrypt(data) {
console.log('type', typeof data);
// 生成随机IV
const iv = CryptoJS.lib.WordArray.random(16); // 生成随机的16字节IV
const encrypted = CryptoJS.AES.encrypt(
JSON.stringify(data),
CryptoJS.enc.Utf8.parse(secretKey),
{
iv: iv, // 使用随机生成的IV
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
}
);
// 返回 IV 和加密后的内容
return {
iv: iv.toString(CryptoJS.enc.Hex),
content: encrypted.toString()
};
}
// AES 解密函数
export function AES_decrypt(encryptedData) {
try {
//json字符串转对象
encryptedData = JSON.parse(encryptedData);
const iv = CryptoJS.enc.Hex.parse(encryptedData.iv);
// 解密
const decrypted = CryptoJS.AES.decrypt(encryptedData.content, CryptoJS.enc.Utf8.parse(secretKey), {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
});
console.log('decrypted', decrypted.toString(CryptoJS.enc.Utf8));
return JSON.parse(decrypted.toString(CryptoJS.enc.Utf8)); // 返回解密后的对象
} catch (error) {
console.error("解密过程中出现错误:", error);
throw new Error("无法解密数据"); // 处理解密错误
}
}
请求和响应拦截器中
instance.interceptors.request.use(function (config) {
// 添加请求之前的逻辑
const token = localStorage.getItem('token')
if (token) {
//如果token不存在则会返回首页进行登录,这的逻辑卸载的vue的全局路由守卫中
config.headers.Authorization = token
}
// AES加密
if (config.data) {
const encryptedData = AES_encrypt(config.data);
config.data = encryptedData; // 将加密后的数据放入请求体
console.log(config.data)
}
return config;
}, function (error) {
// 当请求出现错误的逻辑
return Promise.reject(error);
});
instance.interceptors.response.use(function (response) {
// 首先需要对响应信息进行AES解密
if (response.data) {
const decryptedData = AES_decrypt(JSON.stringify(response.data));
response.data = decryptedData // 将解密后的数据放入响应体
console.log("response.data" + JSON.stringify(response.data))
// response.data = JSON.parse(JSON.parse(decryptedData)); // 将解密后的数据放入响应体
}
// 对响应数据进行处理
// 判断响应数据中的status
if (response.data.status || response.data.message) {
if (response.data.status == 0) {
ElMessage({
message: response.data.message, // 返回的message,如注册成功
type: 'success', // 成功状态为绿色消息提示
})
} else {
ElMessage.error(response.data.message) // 错误状态为红色消息提示
}
}
return response.data;
}, function (error) {
// 当响应出现错误的逻辑
if (error && error.response) {
switch (error.response.status) {
case 400:
ElMessage.error('请求错误')
break
case 401:
ElMessage.error('未授权,请登录')
break
case 403:
ElMessage.error('拒绝访问')
setTimeout(() => {
window.location.href = '/' // 跳转到登录页面
}, 1000);
break
case 404:
ElMessage.error(`请求地址出错: ${error.response.config.url}`)
break
case 500:
ElMessage.error('服务器内部错误')
break
default:
ElMessage.error(`连接出错:${error.response.status}`)
}
}
return Promise.reject(error);
});