npoi 实现类似excel、word自身的加密解密效果

时间:2024-02-24 09:01:09

 

                 最近在做一个文件管理系统,要求上传的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         }

 

                第一次写文章,由于不熟悉这个编辑器,重来了好多遍。 条理可能不太清晰,以后写多了应该逻辑思维就会好点。感谢提供参考文章的大佬们。