如何使用crypto-js對(duì)文件上傳下載進(jìn)行加密處理
由于文件安全問題,要求上傳文件的時(shí)候,把文件流加密后傳遞給后端,且下載的時(shí)候,解密后,方可下載文件。
有兩種方法、一種將文件轉(zhuǎn)base64加密 一種是轉(zhuǎn)二進(jìn)制數(shù)據(jù)加密、由于base64會(huì)將原文件大小變大很多倍,二進(jìn)制不會(huì)、因此推薦使用方法二。
以下是相關(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、文件上傳時(shí)加密
頁(yè)面:
<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"> 請(qǐng)上傳 <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 算法對(duì) 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("上傳失敗, 請(qǐng)重試"); 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)建一個(gè) Blob 對(duì)象 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)建圖片的臨時(shí)url // downloadFile(myUrl,name) var a = document.createElement("a") //新建一個(gè)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、文件上傳時(shí)加密
// 上傳文件 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)建一個(gè) Blob 對(duì)象 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)建圖片的臨時(shí)url // downloadFile(myUrl,name) var a = document.createElement("a") //新建一個(gè)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é)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
vue3動(dòng)態(tài)路由刷新后空白或者404問題的解決
在vue項(xiàng)目中采用動(dòng)態(tài)添加路由的方式,第一次進(jìn)入頁(yè)面會(huì)正常顯示,但是點(diǎn)擊刷新頁(yè)面后會(huì)導(dǎo)致頁(yè)面空白,所以下面這篇文章主要給大家介紹了關(guān)于vue3動(dòng)態(tài)路由刷新后空白或者404問題的解決方法,需要的朋友可以參考下2022-07-07vue?watch中如何獲取this.$refs.xxx節(jié)點(diǎn)
這篇文章主要介紹了vue?watch中獲取this.$refs.xxx節(jié)點(diǎn)的方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08Vue-pdf實(shí)現(xiàn)在線預(yù)覽PDF文件
這篇文章主要為大家詳細(xì)介紹了Vue-pdf實(shí)現(xiàn)在線預(yù)覽PDF文件,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-05-05vue中實(shí)現(xiàn)拖拽排序功能的詳細(xì)教程
在業(yè)務(wù)中列表拖拽排序是比較常見的需求,下面這篇文章主要給大家介紹了關(guān)于vue中實(shí)現(xiàn)拖拽排序功能的詳細(xì)教程,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-08-08