为什么要做加密解密?主要是避免第三方检测系统(WAF)检测出文件有问题,但是文件是用户上传的,我们控制不了这些文件,所以主要是通过对用户上传文件进行加密,后台解密后存储。
前端:
1: 安装crypto-js
npm install crypto-js -save
2: 编写工具:
import CryptoJS from 'crypto-js'
export function encryptFile(file) {
// console.log("32---->: ",CryptoJS.lib.WordArray.random(32).toString(CryptoJS.enc.Hex).substring(0, 32))
// console.log("16---->: ", CryptoJS.lib.WordArray.random(16).toString(CryptoJS.enc.Hex).substring(0, 16))
const key = CryptoJS.enc.Utf8.parse("16ByteFixedKey12"); // 密钥需与后端一致:ml-citation{ref="8" data="citationList"}
// console.log("key->: ",key)
// const iv = CryptoJS.enc.Utf8.parse("f468c06be3fea831"); // IV需与后端一致:ml-citation{ref="8" data="citationList"}
const iv = CryptoJS.enc.Utf8.parse('Fixed16ByteIV456'); // IV需与后端一致:ml-citation{ref="8" data="citationList"}
// console.log("iv---->: ", iv)
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (e) => {
// const fileData = CryptoJS.lib.WordArray.create(e.target.result);
const fileData = new Uint8Array(e.target.result);
const wordArray = CryptoJS.lib.WordArray.create(fileData);
const encrypted = CryptoJS.AES.encrypt(wordArray, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
// 转换为二进制Blob并上传:ml-citation{ref="4,5" data="citationList"}
const encryptedBlob = new Blob([encrypted.toString()], { type: "application/octet-stream" });
const encryptedFile = new File(
[encryptedBlob],
file.name,
{ type: "application/octet-stream" }
);
encryptedFile.uid = file.uid
resolve(encryptedFile); // 返回 Base64 格式密文
};
reader.readAsArrayBuffer(file.raw);
});
}
3: 使用工具
// 收集所有加密的 Promise
const promises = [];
this.$refs.upload.$refs['upload-inner'].fileList.forEach(v => {
if (v.status === 'ready') {
const encryptPromise = encryptFile(v).then(res => {
v.raw = res
return v; // 返回 Promise 的结果
});
promises.push(encryptPromise); // 将 Promise 添加到数组
}
});
// 等待所有加密操作完成后再提交
Promise.all(promises)
.then(() => {
// console.log("加密后")
this.$refs.upload.submit(); // 所有加密完成后提交
})
.catch(error => {
console.error('加密失败:', error);
this.loading = false;
});
后台(grails)
1: 增加包
implementation 'org.bouncycastle:bcprov-jdk15on:1.70'
2: 编写解密方法:
def decryptFile(def file) {
def encryptedFile = file.inputStream
println file.originalFilename
byte[] encryptedData = IOUtils.toByteArray(encryptedFile)
// 将 Base64 字符串解码为原始密文字节数组
String encryptedString = new String(encryptedData, "UTF-8")
byte[] decodedData = java.util.Base64.getDecoder().decode(encryptedString)
// 初始化解密器:ml-citation{ref="8" data="citationList"}
SecretKeySpec secretKey = new SecretKeySpec("16ByteFixedKey12".getBytes("UTF-8"), "AES")
IvParameterSpec ivSpec = new IvParameterSpec("Fixed16ByteIV456".getBytes("UTF-8"))
Security.addProvider(new BouncyCastleProvider())
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC")
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec)
// 执行解密:ml-citation{ref="8" data="citationList"}
return cipher.doFinal(decodedData);
// byte[] decryptedBytes = cipher.doFinal(decodedData)
//
// // 保存解密文件:ml-citation{ref="5" data="citationList"}
// new File("/Users/zhangjiayu/Desktop/project/files/test.pdf").withOutputStream { it.write(decryptedBytes) }
}
注意:
前后台使用的key【16ByteFixedKey12】和IV【Fixed16ByteIV456】需要保持一致