如何使用crypto-js對文件上傳下載進(jìn)行加密處理
由于文件安全問題,要求上傳文件的時候,把文件流加密后傳遞給后端,且下載的時候,解密后,方可下載文件。
有兩種方法、一種將文件轉(zhuǎn)base64加密 一種是轉(zhuǎn)二進(jìn)制數(shù)據(jù)加密、由于base64會將原文件大小變大很多倍,二進(jìn)制不會、因此推薦使用方法二。
以下是相關(guān)代碼:
方法一
1、引入crypto-js
并封裝加密、解密的方法,具體代碼如下:
// utils/jsencrypt.js
import CryptoJS from 'crypto-js';
// DES加密
export const encryptByDES = (message, key) => {
var keyHex = CryptoJS.enc.Utf8.parse(key);
var encrypted = CryptoJS.AES.encrypt(message, keyHex, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
return encrypted.toString();
}
// DES解密
export const decryptByDES = (ciphertext, key) => {
var keyHex = CryptoJS.enc.Utf8.parse(key);
// direct decrypt ciphertext
var decrypted = CryptoJS.AES.decrypt({
ciphertext: CryptoJS.enc.Base64.parse(ciphertext)
}, keyHex, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
return decrypted.toString(CryptoJS.enc.Utf8);
}2、文件上傳時加密
頁面:
<el-upload
action="#"
:before-upload="handleBeforeUpload"
:file-list="fileList"
:limit="1"
:on-error="handleUploadError"
:on-exceed="handleExceed"
:on-success="handleUploadSuccess"
:show-file-list="false"
:headers="headers"
:http-request="handleFileUpload"
class="upload-file-uploader"
ref="upload"
>
<!-- 上傳按鈕 -->
<el-button size="mini" type="primary" :loading="loading">選取文件</el-button>
<!-- 上傳提示 -->
<div class="el-upload__tip" slot="tip" v-if="showTip">
請上傳
<template v-if="fileSize"> 大小不超過 <b style="color: #f56c6c">{{ fileSize }}MB</b> </template>
<template v-if="fileType"> 格式為 <b style="color: #f56c6c">{{ fileType.join("/") }}</b> </template>
的文件
</div>
</el-upload>上傳文件(加密文件):
首先使用FileReader中readAsDataURL將上傳的文件流轉(zhuǎn)成base64字符串,然后使用加密事件將base64字符串加密,傳遞給后端。
// 上傳文件
handleFileUpload(file){
this.loading = true
let reader = new FileReader()
reader.readAsDataURL(file.file) // 讀取base64
reader.onload = ()=>{
// reader.result 讀取base64
// 使用 AES 算法對 reader 進(jìn)行加密
let encrypted = encryptByDES(reader.result, 'abcdefghijklmno12345678910234567') // 此加密key可自定義
this.base64String = encrypted
// 獲取文件類型
this.fileTypes = file.file.name.substring(file.file.name.lastIndexOf("."))
let params = {
fileName:file.file.name,
fileType:this.fileTypes,
fileSize:file.file.size,
base64:this.base64String // 將加密后的文件字符串傳給后端
}
getFileUpload(params).then((res)=>{
this.loading = false
this.$message.success("上傳成功");
this.fileName=res.fileName
console.log(this.fileName,'this.fileName')
this.$emit("input", res.fileId);
this.$emit('fileName',this.fileName)
}).catch((error)=>{
this.loading = false
this.$message.error("上傳失敗, 請重試");
console.log(error,'error')
this.fileList = []
this.list = []
})
}
},下載文件(解密文件):
先將獲取到的加密串解密,然后將base64串轉(zhuǎn)成blob格式,然后下載文件,具體代碼如下:
// 通過接口獲取到加密字符串files
keyFiles(params).then((files)=>{
// 將加密字符串files解密
let base64Url = decryptByDES(files,'abcdefghijklmno12345678910234567')
// 將解密到的base64字符串轉(zhuǎn)成blob格式
let blob = this.base64Toblob(base64Url)
// 下載文件
this.blobDownload(blob,this.listParams.fileName)
this.$set(row, 'loading', false)
})base64Toblob(dataURI) {
// 將 dataURI 分割為類型和數(shù)據(jù)兩部分
var parts = dataURI.split(",");
var type = parts[0].match(/:(.*?);/)[1];
var data = parts[1];
// 將 base64 數(shù)據(jù)解碼為二進(jìn)制數(shù)據(jù)
var byteString = atob(data);
// 將二進(jìn)制數(shù)據(jù)轉(zhuǎn)換為類型化數(shù)組
var arrayBuffer = new ArrayBuffer(byteString.length);
var intArray = new Uint8Array(arrayBuffer);
for (var i = 0; i < byteString.length; i++) {
intArray[i] = byteString.charCodeAt(i);
}
// 創(chuàng)建一個 Blob 對象
var blob = new Blob([intArray], { type: type });
return blob;
},blobDownload(blob,fileName){
// 判斷瀏覽器類型
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
// 如果是 IE 瀏覽器,使用 msSaveOrOpenBlob 方法
window.navigator.msSaveOrOpenBlob(blob, fileName);
} else {
var myUrl = URL.createObjectURL(blob); //創(chuàng)建圖片的臨時url
// downloadFile(myUrl,name)
var a = document.createElement("a") //新建一個a鏈接
a.setAttribute("href",myUrl) // a鏈接的url為圖片的url
a.setAttribute("download",fileName)
a.setAttribute("target","_blank")
let clickEvent = document.createEvent("MouseEvents");
clickEvent.initEvent("click", true, true);
a.dispatchEvent(clickEvent);
}
},由于要支持ie瀏覽器,注意crypto-js的版本,一開始使用4.1.1 不支持ie,后面改成4.0.0即可。
方法二
由于將文件轉(zhuǎn)成base64加密后使文件大小比之前大了很多倍,存到服務(wù)器很不友好,于是使用二進(jìn)制進(jìn)行加解密、保持與之前大小一致,具體如下:
1、封裝加密、解密的方法
import CryptoJS from 'crypto-js';
import CryptoU8array from "./crypto-en"
var key = CryptoJS.enc.Utf8.parse("1111111111111111"); //十六位十六進(jìn)制數(shù)作為秘鑰
var iv = CryptoJS.enc.Utf8.parse('1111111111111111');//十六位十六進(jìn)制數(shù)作為秘鑰偏移量
// 使用 AES 進(jìn)行文件加密
export function encryptFile(word) {
const messageWordArray = CryptoU8array.u8array.parse(word);
var encrypted = CryptoJS.AES.encrypt(messageWordArray, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
let encryptedBytes = encrypted.ciphertext
return CryptoU8array.u8array.stringify(encryptedBytes)
}
// 使用 AES 進(jìn)行文件解密
export function decryptFile(word) {
const messageWordArray = CryptoU8array.u8array.parse(word);
var dcBase64String = messageWordArray.toString(CryptoJS.enc.Base64);
var decrypt = CryptoJS.AES.decrypt(dcBase64String, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
// var decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
return CryptoU8array.u8array.stringify(decrypt)
} // crypto-en.js
import CryptoJS from 'crypto-js'
CryptoJS.enc.u8array = {
/**
* Converts a word array to a Uint8Array.
*
* @param {WordArray} wordArray The word array.
*
* @return {Uint8Array} The Uint8Array.
*
* @static
*
* @example
*
* var u8arr = CryptoJS.enc.u8array.stringify(wordArray);
*/
stringify: function (wordArray) {
// Shortcuts
var words = wordArray.words
var sigBytes = wordArray.sigBytes
// Convert
var u8 = new Uint8Array(sigBytes)
for (var i = 0; i < sigBytes; i++) {
var byte = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff
u8[i] = byte
}
return u8
},
/**
* Converts a Uint8Array to a word array.
*
* @param {string} u8Str The Uint8Array.
*
* @return {WordArray} The word array.
*
* @static
*
* @example
*
* var wordArray = CryptoJS.enc.u8array.parse(u8arr);
*/
parse: function (u8arr) {
// Shortcut
var len = u8arr.length
// Convert
var words = []
for (var i = 0; i < len; i++) {
words[i >>> 2] |= (u8arr[i] & 0xff) << (24 - (i % 4) * 8)
}
return CryptoJS.lib.WordArray.create(words, len)
}
}
export default {
u8array: CryptoJS.enc.u8array
}2、文件上傳時加密
// 上傳文件
handleFileUpload(file) {
this.upload.isUploading = true
let reader = new FileReader()
reader.readAsArrayBuffer(file.file) // 以二進(jìn)制數(shù)據(jù)讀取文件
reader.onload = () => {
var fileContent = new Uint8Array(reader.result) // 轉(zhuǎn)成Uint8Array類型
var encryptedContent = encryptFile(fileContent); // 加密
console.log(encryptedContent, '加密后串');
let blobType = file.file.type
let fileName = file.file.name
let blob = this.atobToblob(encryptedContent, blobType) // 將加密后串轉(zhuǎn)blob
let blobToFile = new File([blob], fileName, {
type: blobType,
lastModified: Date.now()
}); // 得到加密文件
let formData = new FormData();
formData.append("file", blobToFile); // 傳給后端即可
}
},
atobToblob(intArray,type) {
// 創(chuàng)建一個 Blob 對象
var blob = new Blob([intArray], { type: type });
return blob;
}3、解密并下載
// 解密邏輯 file-二進(jìn)制-解密-blob-file
desFileList() {
this.files.map((item) => {
let readers = new FileReader()
readers.readAsArrayBuffer(item.url) // item.url 為加密后的串
readers.onload = () => {
var fileContent = new Uint8Array(readers.result)
// console.log(fileContent, 'fileContent加密前');
var encryptedContent = decryptFile(fileContent);
console.log(encryptedContent, '解密后3333');
let blob = atobToblob(encryptedContent, item.url.type)
console.log(blob,'blob');
let blobToFile = new File([blob], item.url.name, {
type: item.url.type,
lastModified: Date.now()
})
item.url = blobToFile
item.name = item.url.name
item.tag=1
// blobDownload(blob,blobToFile.name)
}
})
console.log(this.files,'this.files');
setTimeout(() => {
this.$refs.files.setFileList(this.files)
}, 500);
},
export function blobDownload(blob, fileName) {
// 判斷瀏覽器類型
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
// 如果是 IE 瀏覽器,使用 msSaveOrOpenBlob 方法
window.navigator.msSaveOrOpenBlob(blob, fileName);
} else {
var myUrl = URL.createObjectURL(blob); //創(chuàng)建圖片的臨時url
// downloadFile(myUrl,name)
var a = document.createElement("a") //新建一個a鏈接
a.setAttribute("href", myUrl) // a鏈接的url為圖片的url
a.setAttribute("download", fileName)
a.setAttribute("target", "_blank")
let clickEvent = document.createEvent("MouseEvents");
clickEvent.initEvent("click", true, true);
a.dispatchEvent(clickEvent);
}
}總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
vue?watch中如何獲取this.$refs.xxx節(jié)點
這篇文章主要介紹了vue?watch中獲取this.$refs.xxx節(jié)點的方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-08-08

