技术开发 频道

用ASP.NET实现文件的保护性下载基础篇

  九、控制下载

  下面,我们开始讲述如何编写一个用于某些文件请求的处理程序,以及该处理程序的安装方法。我们的处理程序的功能很简单,它只是将请求重定向到其他地方而已。ASP.NET还提供了另外一种文件扩展名即ASHX,它无需安装到web.config文件中。我们可以创建一个以这个扩展名结尾的类,来实现IHttpHandler接口,并就直接导航至该类。实际上它与一个页面非常类似,只是它不会使用Web表单和Code-Behind类,所以它是一种更加简洁的方案。

  现在,我们创建一个新的处理程序称为Download.ashx,并让用户浏览到该处理程序的位置,同时在QueryString参数中规定一些信息。下面的URL就是下载链接:

  ~/Downloads/Download.ashx?Product=101

  这个URL表示下载与产品101有关的文件。用户或者链接可以访问上述URL来试图下载一个文件,这时,该处理程序的ProcessRequest方法就会执行。

  利用标准Forms身份验证对用户身份进行验证,这样就能访问在我们站点上下文中的User对象。请记住,HTTP上下文会传递给该处理程序的ProcessRequest方法,所以能访问到所需的内容。对象User允许我们获得使用User.Identity.Name的授权用户的名称,还有,我们还可以使用该方法访问User表中的用户。访问用户的名称,我们要使用User.Identity.IsAuthenticated的值来检查他们是否已经过身份认证,如果没有,将其重定向到“access denied”。此外,我们还要访问请求的产品号码,代码如下所示:

context.Request.QueryString["Product"]

  这样,我们就取得了产品号码和用户名。 有了这两者,我们就可以访问UserProducts表并确定这个用户是否购买过这个产品。此外,这个表还存储有该产品的文件名。

  既然有了用户名和产品号码,并通过它们确定除了用户购买情况。如果该用户没有购买相应的产品,我们就将其重定向到前面的处理程序,并返回一个访问拒绝页面。为简洁起见,我们将其重定向到一个告知他们还没有购买过此产品的页面,并告知如何进行购买。

  如果确定该用户购买了这个产品,可以通过ProductFileName字段了解该用户可以查看哪些文件。这里,我们没有存储完整的路径,只是存储了文件名。如果需要,我们可以从web.config中的设置来获得该文件夹,所以最终获得了完整的文件路径和名称,并授权下载。 下面我们通过称为StartDownload方法来完成此任务:

private void StartDownload(
       HttpContext context,
string downloadFile)
   {
         context.Response.Buffer
= true;
         context.Response.Clear();
         context.Response.AddHeader(
            
"content-disposition",
            
"attachment; filename=" + downloadFile);
         context.Response.ContentType
=
            
"application/zip";
         context.Response.WriteFile(
            
"~/Downloads/Files/" + downloadFile);
   }

  这里的ProcessRequest方法会调用StartDownload方法,完整的Download.ashx代码如下所示:

<%@ WebHandler Language="C#" Class="Download" %>
using System;
using System.Web;
public class Download : IHttpHandler
{
  
public void ProcessRequest (HttpContext context)
   {
      
if (context.User.Identity.IsAuthenticated)
      {
        
if(context.Request.QueryString["Product"] != null
            
&& context.Request.QueryString["Product"] != "")
         {
            
int productID = Convert.ToInt16(
               context.Request.QueryString[
"Product"]);
            
string userName = context.User.Identity.Name;
            UserProduct product
= UserProductFactory.GetProductByUser(
               userName, productID);
            
if(product != null)
               StartDownload(product.FileName);
            
else
               context.Response.Redirect(
                  
"~/Downloads/Files/AccessDenied.aspx");
         }
      }
   }

  
public bool IsReusable
   {
      
get
      {
        
return false;
      }
   }
  
private void StartDownload(string downloadFile)
   {
      context.Response.Buffer
= true;
      context.Response.Clear();
      context.Response.AddHeader(
        
"content-disposition",
        
"attachment; filename=" + downloadFile);
      context.Response.ContentType
= "application/zip";
      context.Response.WriteFile(
        
"~/Downloads/Files/" + downloadFile);
   }
}

  这个方法会收到文件的名称以及HttpContext。由此处,我们将清空响应缓冲区,设置一个新的头部,然后设置内容类型。最后,使用WriteFile方法输出该文件,最终用户会收到一个文件保存或打开窗口。

  注意,使用WriteFile会输出ZIP 文件,而是要Response.Redirect则会把用户重定向到访问拒绝页面。使用这种技术的时候,聪明的用户可以绕过安全检查而直接导航至Download.ashx文件。但即使它们设法直接浏览到ZIP 文件,也会被FileDenialHandler处理程序重定向到访问拒绝页面。

  注意这两种类型处理程序的区别,一个是可以放在外部组件中的标准C#(或者VB.NET)类,如果您需要编写可重用的处理程序的时候,这种类型比较理想,因为您可以把它们编译成一个动态链接库,并在不同的站点之间分享。当然,我们需要在web.config文件中对它们进行注册。对于ASHX类型的处理程序,可以像ASPX页面一样添加到站点中。事实上,我们可以使用其他技术来完成类似Download.ASHX的功能,但是ASHX处理程序是更加简洁的解决方案。

  十、小结

  使用ASP.NET保护文件下载的所有方法中,利用HTTP处理程序是最重要的一种。通过与其他技术相结合,我们不仅能够防止非授权用户下载文件,还能在处理用户下载文件试图时获得绝对控制权,希望本文的内容对您能够有所帮助。

0
相关文章