vue对文件进行加密,后台解密后保存

发布于:2025-03-29 ⋅ 阅读:(31) ⋅ 点赞:(0)

为什么要做加密解密?主要是避免第三方检测系统(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】需要保持一致