前端zip.js实现加密打包上传文件

2,037 阅读1分钟

背景:一方面,部分系统对文件的私密性和安全性要求较高,文件通过互联网传输,若加密密码保存在服务端,依旧存在一定风险,故项目内实现前端打包加密,由上传者输入密钥,在前端完成加密打包,用户保存文件密钥,下载时手动输入密钥并解压文件。另一方面,传输压缩包到客户端,节约了带宽,节约了传输时间。

使用的库: zip.js 以下为vue的实现方案:

  • 加密上传文件
import * as zip from '@zip.js/zip.js'
...
...
methods: {
  async handleZipFile () {
    const controller = new AbortController()
    const signal = controller.signal
    var zipWriter = new zip.ZipWriter(new zip.BlobWriter('application/zip'))
    await Promise.all(_.map(this.files, async (file) => {
      await zipWriter.add(file.name, new zip.BlobReader(file.raw), {
        bufferedWrite: true,
        password: this.password,
        signal,
        zipCrypto: true,
        onprogress: (index, max) => {
          const percent = parseInt(index / max * 100 || 0)
          this.loadingText = `正在打包文件${file.name},进度为${percent}%`
        }
      })
    }))
    let [err, data] = await callAsync(zipWriter.close())
      if (data) {
        await this.uploadFile(new File([data], this.name + '.zip'))
      }
    },
    async uploadFile (file) {
      let formdata = new FormData()
      formdata.append('file', file)
      formdata.append('type', this.type) // 其他字段
      let [err, res] = await callAsync(axios({
        url: `/api/upload`,
        method: 'post',
        data: formdata,
        headers: { 'Content-Type': 'multipart/form-data' },
        timeout: 0,
        onUploadProgress: progressEvent => {
          let percent = (progressEvent.loaded / progressEvent.total * 100 | 0)
          this.loadingText = `正在上传文件${file.name},进度为${percent}%`
        }
      }))
      if (err) {
        if (axios.isCancel(err)) {
          this.$message.success('已取消上传')
        } else {
          this.$message.error('文件上传失败' + err)
        }
      } else {
        this.loadingText = ''
      }
    }
}

  • 解密解压文件

methods: {
  async getZipFiles (password, fileUrl, projectId) {
    try {
      const reader = new zip.ZipReader(new zip.HttpReader(fileUrl, {}), {
        password: password
      })
      const entries: any = await reader.getEntries()
      await reader.close()
      return [null, { password: password, files: entries }]
    } catch (err) {
      return [{ msg: err.toString() }, null]
    }
  }
}