最近在做一個文件管理系統,要求上傳的excel、word、pdf 文件加密存在服務器上。在系統里下載可以不輸密碼直接打開,在服務器上點開文件必須要輸密碼。要考慮做好一勞永逸、也不能用收費的。以前沒做過關於文檔加密的東西,網上搜了好多, 可以實現加密解密的大致分為3種:
1:Spire
參考地址:https://zhidao.baidu.com/question/560428556.html
有免費的,我下載dll做完后發現有水印,因為公司的文件都是很正式的文件,所以果斷放棄了它。這款能實現多種類型的文件加密解密,如果公司願意花錢買,用這個還是很不錯的。可以給我們開發人員省很多事。
使用步驟:免費版本可以在官網下載,然后把dll文件引入項目就可以使用了( Free Spire.Xls)。
以下幾個網址介紹的很詳細,
https://www.cnblogs.com/asxinyu/p/4346907.html
https://www.cnblogs.com/cjm123/p/8660810.html
上代碼:
using 添加引用。 //加密 //初始化一個工作簿並加載一個工作簿實例 Workbook book = new Workbook(); book.LoadFromFile("d://test.xls"); //為工作簿設置訪問密碼 book.Protect("123"); //保存並打開文檔 book.SaveToFile("d://test.xls", ExcelVersion.Version2013); //解密 //初始化一個Workbook實例 Workbook workbook = new Workbook(); //輸入密碼並加載文檔 workbook.OpenPassword = ("123"); workbook.LoadFromFile("d://test.xls", ExcelVersion.Version2013); //取消保護 workbook.UnProtect(); //保存 workbook.SaveToFile("d://test.xls", ExcelVersion.Version2013) //word加密 // savePath絕對路徑 //doc 可以,但是眉頭 加了一行水印 。docx沒有被加密 //Document document = new Document(); //document.LoadFromFile(@"" + savePath); //document.Encrypt("000"); //document.SaveToFile(savePath);
2:C# Office組件 dll word.dll excel.dll
沒用這個原因是:
要保證機器本身安裝了office.因為客戶分布比較廣, 不能保證每個用戶電腦都安裝了這個組件。所以沒有用代碼試。
3:NPOI
這個是免費的,但是我搜到的可以加密的格式並不多,但是由於系統中pdf 文件極少出現,我只需要操作xlsx、docx 格式的文件就好,所以還是 可以滿足我的需求,就用了這個。在做的過程中只找到了如何用npio 加密,沒有看到解密的。 只加密不能解密也不行啊,后來搜了好多還是沒找到解決辦法,靈機一動,把加密的參數賦為null, 下載下來的文件就直接打開了。終於在答應交東西日期之前把功能實現了。然后就想着記錄一下給別人參考,別人在着急用的時候業務相同可以直接拿去用了 。 自己做了這幾年的開發,每次都是搜別人的東西用,今天開始也記錄些東西給別人提供方便。
看到有的文章說xls也可以實現,但是我在試 的過程中,並沒有成功,不知道是不是dll 版本不一樣導致。
介紹如何引用: https://blog.csdn.net/weixin_39029925/article/details/75389075
參考的文章:https://www.cnblogs.com/teamblog/p/6158140.html
上代碼: mvc、uploadify文件插件。(以下代碼只能保證實現 xlsx、docx 格式的加密解密)
1 //此部分是加密的方法。 2 #region 表格上傳下載頁的文件上傳 3 4 int SetFileSize = Convert.ToInt32(ConfigurationManager.AppSettings["SetFileSize"]); 5 6 /// <summary> 7 /// 文件上傳 8 /// </summary> 9 /// <returns></returns> 10 public JsonResult UpLoadFile() 11 { 12 HttpFileCollectionBase file = Request.Files; 13 string url = ""; 14 15 string fileName = "";//最終的文件名 16 string Name = ""; 17 string FilePsd = "";//文件加密的密碼 18 string DepName = HttpUtility.UrlDecode(Request.QueryString["DepName"].Trim()); 19 string ProjectName = HttpUtility.UrlDecode(Request.QueryString["ProjectName"].Trim()); 20 string Updatetime = Request.QueryString["Updatetime"]; 21 string FormId = Request.QueryString["FormId"]; 22 23 if (Updatetime.Contains("中國標准時間")) 24 { 25 Updatetime = Updatetime.Trim().Replace("GMT 0800 (中國標准時間)", ""); 26 } 27 else 28 { 29 Updatetime = Updatetime.Trim().Replace("GMT 0800 (China Standard Time)", ""); 30 31 } 32 //中文:Wed Aug 07 2019 16:27:32 GMT+0800 (中國標准時間) 33 //英文:Mon Sep 02 2019 09:11:01 GMT 0800 (China Standard Time) 34 string FileName = HttpUtility.UrlDecode(Request.QueryString["FileName"].Trim()); 35 36 string fileType = ""; 37 TimeSpan span = DateTime.Now - Convert.ToDateTime(Updatetime); 38 if (span.TotalHours > 24) 39 { 40 return Json(new { url = "", name = "-2" });//該文件在24小時內沒有修改過不能上傳 41 } 42 if (file.Count > 0) 43 { 44 if (file[0].ContentLength != 0) 45 { 46 Name = FileName; 47 fileType = Name.ToString().Substring(Name.LastIndexOf(".")); 48 int length = Name.Length - fileType.Length; 49 Name = Name.ToString().Substring(0, length); 50 if (Name.Contains('.')) 51 { 52 fileName = Name.ToString().Substring(0, length).Remove('.') + Encryption.GenerateRandomNumber(10);//表格名稱+隨機數; 53 } 54 else 55 { 56 fileName = Name + Encryption.GenerateRandomNumber(10);//表格名稱+隨機數; 57 } 58 if (fileType != "*.xls" || fileType != "*.xlsx" || fileType != "*.pdf") 59 { 60 //DailyForm/項目名稱/部門名稱/年/月/文件 61 string filePath = ConfigurationManager.AppSettings["DailyForm"] + "/" + ProjectName + "/" + DepName 62 + "/" + ComFunction.GetYear(DateTime.Now.ToString()) 63 + "/" + ComFunction.GetMonth(DateTime.Now.ToString()) 64 + "/" + fileName + fileType; 65 url = filePath; 66 if (!Directory.Exists(Server.MapPath(filePath))) 67 { 68 Directory.CreateDirectory(Server.MapPath(filePath).Substring(0, Server.MapPath(filePath).LastIndexOf('\\'))); 69 } 70 try 71 { 72 string savePath = Server.MapPath(filePath); 73 //把傳入的原始文件存到文件夾。 74 file[0].SaveAs(savePath); 75 76 //判斷該表格是否是敏感數據 77 string result = SQLHelper.GetFieldValue2("File", "t_able", " and Id=@Id", new List<KeyValue> { new KeyValue { Key = "@Id", Value = FormId } });//是否是敏感的 0 不是 1 是 78 79 if (result != "1") 80 { 81 FilePsd = "0"; 82 } 83 else //需要加密文件 84 { 85 FilePsd = Encryption.GenerateRandomNumber(6); 86 87 88 //====================================這里是加密主要的代碼================================== 89 90 //如果類型是.docx 、 xlsx,直接加密 Nipo 91 if (fileType == ".docx" || fileType == ".xlsx") 92 { 93 using (OfficeCryptoStream stream = OfficeCryptoStream.Open(@"" + savePath)) 94 { 95 stream.Password = FilePsd; 96 bool a = stream.Encrypted; 97 stream.Save(); 98 } 99 } 100 //轉換格式還未實現,搜了一些辦法,都不適用。等以后做出來了來更新。 101 else //如果是 *.xls; *.pdf;*.doc; *.rtf;先轉換成 docx、xlsx、 102 { 103 if (fileType == ".pdf") 104 { 105 //Workbook workbook1 = new Workbook(); 106 //workbook1.SaveCopyAs(savePath); 107 //workbook1.Password = "123"; 108 //workbook1.SaveAs(); 109 //workbook1.Unprotect("123"); 110 111 } 112 } 113 114 115 } 116 117 118 119 120 //初始化一個工作簿並加載一個工作簿實例 121 //Workbook book = new Workbook(); 122 //book.LoadFromFile(savePath);//"test.xls" 123 124 ////為工作簿設置訪問密碼 125 //book.Protect("147"); 126 127 ////保存並打開文檔 128 //book.SaveToFile(savePath, ExcelVersion.Version2013); 129 130 131 // Workbook workbook = new Workbook(); 132 //workbook.LoadFromFile(@"" + savePath); 133 //workbook.SaveToFile(savePath.Substring(0, savePath.Length-3)+ "xlsx", ExcelVersion.Version97to2003);//目標文件.xlsx 134 135 136 137 138 139 140 //正確 141 //doc、 可以,但是眉頭 加了一行標志 docx沒有被加密 142 //Document document = new Document(); 143 //document.LoadFromFile(@"" + savePath); 144 //document.Encrypt("000"); 145 //document.SaveToFile(savePath); 146 147 148 149 150 //初始化一個Document類實例並加載需要加密的Word文檔 151 //Document doc = new Document(@"C:\Users\Administrator\Desktop\sample.docx"); 152 // Document doc = new Document(Server.MapPath(filePath)); 153 //Document doc = new Document(@"D:\32324.docx"); 154 ////設置打開Word文檔的密碼 155 //doc.Encrypt("123"); 156 ////保存並打開文檔 157 //doc.SaveToFile( "sds.docx", FileFormat.Docx); 158 159 if (new FileInfo(Server.MapPath(filePath)).Length <= SetFileSize)// 160 { 161 } 162 else 163 { 164 //大於XM 165 System.IO.File.Delete(Server.MapPath(filePath)); 166 } 167 168 } 169 catch (Exception ex) 170 { 171 } 172 Name = Name + fileType; 173 } 174 else 175 { 176 return Json(new { url = "", name = "-1" });//格式不合法 177 } 178 } 179 } 180 url = System.Web.HttpUtility.UrlEncode(url); 181 Name = System.Web.HttpUtility.UrlEncode(Name + "&" + FilePsd); 182 return Json(new { url = url, name = Name }); 183 } 184 #endregion
此部分是解密的方法,大致思路是:獲取到要下載的文件路徑,復制文件(a)到另一個文件夾(b),把b的文件解密保存,去下載b 的文件。因為有服務在監控a文件夾 的文件,會把他復制到另一個服務器。后台用代碼把文件復制一份再解密后下載解密的文件。 這樣能保證原始文件密碼始終存在,服務監控復制文件不會把解密的文件一起復制走了。
1 /// <summary> 2 /// 原文件下載和操作員上傳的文件下載方法 3 /// </summary> 4 /// <param name="UploadDownloadId">上傳下載ID</param> 5 /// <param name="FilePath"></param> 6 /// <param name="FormName"></param> 7 /// <param name="type">0:下載提交的日常表格,1下載表格模板</param> 8 /// <param name="type2">0: 上傳下載頁面,1審批頁面</param> 9 public void DownFile(string FilePath, string FormName, int UploadDownloadId, int type, int type2) 10 { 11 //判斷是否有下載權限 12 EnUser UserInfo = Session["UserInfo"] as EnUser; 13 14 DateTime DownTime = DateTime.Now; 15 EnUploadDownload UploadDownload = new EnUploadDownload(); 16 try 17 { 18 string DownFormName = ""; 19 string FileCompletePath = "";//原文件完整路徑 20 string CopyFileCompletePath = "";//復制文件完整路徑 21 string FilePsd = "";//文件密碼 22 string NewPath = "";//生成臨時新的文件。 23 bool ExistFile = false; 24 //下載輸出 25 if (type == 1) 26 { 27 DownFormName = "表格模板___" + FormName; 28 } 29 else 30 { 31 DownFormName = FormName; 32 //先把文件解密存在新的文件夾下載完畢然后刪掉 33 //根據UploadDownloadId 查找需不需要解密,0不需要,其他需要。 34 FilePsd = SQLHelper.GetFieldValue2("FilePwd", "t_table", " and Id=@Id", new List<KeyValue> { new KeyValue { Key = "@Id", Value = UploadDownloadId } });//是否需要解密的 0 不是 其他 是 35 if (FilePsd != "0" && FilePsd != "" && (FilePath.Contains(".pdf")!=true))//需要解密文件 36 { 37 ExistFile = ComFunction.ExistFilePath(FilePath); 38 if (ExistFile ) //如果文件存在並且文件不是pdf 39 { 40 string[] arrry = FilePath.Split('/'); 41 for (int i = 0; i < arrry.Length; i++) 42 { 43 if (i > 1 && i != 7) 44 { 45 NewPath = NewPath + '/' + arrry[i]; 46 } 47 } 48 NewPath = ("~/DeclassifiedFile" + NewPath + '/' + Encryption.GenerateRandomNumber(4) + arrry[7]).Trim(); 49 50 //路徑不存在創建路徑 51 if (!Directory.Exists(Server.MapPath(NewPath))) 52 { 53 Directory.CreateDirectory(Server.MapPath(NewPath).Substring(0, Server.MapPath(NewPath).LastIndexOf('\\'))); 54 } 55 //獲取完整路徑 56 FileCompletePath = ComFunction.CompletePath(FilePath); 57 CopyFileCompletePath = ComFunction.CompletePath(NewPath); 58 59 //====================================這里是解密主要的代碼================================== 60 61 //復制加密的文件到其他地址 62 FileInfo fi1 = new FileInfo(FileCompletePath); 63 FileInfo fi2 = new FileInfo(CopyFileCompletePath); 64 fi1.CopyTo(CopyFileCompletePath); 65 66 ////解密 67 using (OfficeCryptoStream stream = OfficeCryptoStream.Open(@"" + CopyFileCompletePath, FilePsd)) 68 { 69 stream.Password = null; 70 bool b = stream.Encrypted; 71 stream.Save(); 72 FilePath = NewPath; 73 } 74 } 75 } 76 else 77 { 78 79 } 80 } 81 //執行下載方法 82 string result = ComFunction.DownLoadFile(DownFormName, FilePath); 83 string remark = ""; 84 if (FilePsd != "0")//需要解密文件 85 { 86 //刪除零時被解密的文件 87 if (CopyFileCompletePath.Length > 1) 88 { 89 90 bool IsDelete = DeleteFile(CopyFileCompletePath); 91 92 if (!IsDelete) 93 { 94 string filePath = "~/Log/"; 95 96 if (!Directory.Exists(Server.MapPath(filePath))) 97 { 98 Directory.CreateDirectory(Server.MapPath(NewPath).Substring(0, Server.MapPath(filePath).LastIndexOf('\\'))); 99 } 100 LogHelper.OtherErroLogText2("下載文件時,備份文件沒有被刪除,文件路徑:" + CopyFileCompletePath, ComFunction.CompletePath(filePath)); 101 } 102 } 103 } 104 105 if (!result.Contains("-1")) 106 { 107 108 if (type2 == 0) 109 { 110 remark = "在上傳下載頁面"; 111 } 112 else if (type2 == 1) 113 { 114 remark = "在審批頁面"; 115 } 116 else if (type2 == 3) 117 { 118 remark = "在審批記錄頁面"; 119 120 } 121 else if (type2 == 4) 122 { 123 remark = "在日常表格列表查詢頁面"; 124 125 } 126 else if (type2 == 5) 127 { 128 remark = "在打印頁面"; 129 130 } 131 else if (type2 == 6) 132 { 133 remark = "在打印模板詳情頁_表格"; 134 135 } 136 137 else if (type2 == 7) 138 { 139 remark = "在打印模板詳情頁_附件"; 140 141 } 142 143 144 145 remark = remark + (type == 0 ? "下載了提交的日常表格:" : "下載了表格模板:"); 146 string optName = "下載"; 147 if (type2 == 7 || type2 == 6) 148 { 149 optName = "打印__下載"; 150 } 151 // 添加數據到上傳下載表、表格操作記錄表 152 int count = BLL_FormOperationRecord.AddFormOperationRecord(UploadDownloadId, UserInfo.Id, DownTime, optName, remark + FormName); 153 154 if (count > 0) 155 { 156 157 } 158 else 159 { 160 161 //添加失敗 162 163 } 164 165 } 166 else 167 { 168 } 169 } 170 171 172 173 catch (Exception ex) 174 { 175 176 //寫入錯誤日志 177 LogHelper.WriteExceptionLogToText(ex); 178 } 179 180 }
第一次寫文章,由於不熟悉這個編輯器,重來了好多遍。 條理可能不太清晰,以后寫多了應該邏輯思維就會好點。感謝提供參考文章的大佬們。