最近在做一个文件管理系统,要求上传的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 }
第一次写文章,由于不熟悉这个编辑器,重来了好多遍。 条理可能不太清晰,以后写多了应该逻辑思维就会好点。感谢提供参考文章的大佬们。