现在这个条目将所有的压缩文件请求转发给新的处理程序,因此立即将请求重定向到“Access Denied”页面。即使在本例中跳过该IIS条目,它仍然会照常工作,因为这些事情都交由我们的处理程序了。 然而,我们想要的效果是让系统在判定匿名用户访问非法的ZIP 文件之前,首先把他们导航至登录页面。
如果检查框架目录中的web.config文件,就会发现一列处理常见文件扩展名用于ASP.NET的处理程序。定义这个文件中的部分的处理程序决定了IIS如何恰当地转发ASPX页面、ASMX Web 服务以及所有其他文件。 这个处理程序列表还定义了哪些文件扩展名是禁用的,例如*.config。事实上,可以利用一个称为HttpForbiddenHandler的处理程序来禁用所有以扩展名.config结尾的文件,并自动显示一个“HTTP 403error Forbidden :Access is denied ”页面。
所以您可能问,无什么不只用Microsoft提供的处理程序来处理压缩文件呢? 答案是,当然可以用,不过我们需要自己的“access denied”页面,这样通过定制我们自己的拒绝页面,就能跟我们的网站风格保持一致。在某些情况下,我们还想为用户提供更多的信息,甚至向管理员发送“未经授权的尝试”类电子邮件。
这里只是防止下载所有的压缩文件,但是我们实际想要做的是什么?对了,我们要取得从我们站点上文件下载方式的绝对控制权。我们不想让用户直接浏览压缩文件。通过表结构,我们可建立一个项目、用户列表,以及每个用户购买产品的关系表。因此如果我们有一个用户名和一个产品序列号,就可以通过一个简单的数据库查询来判断这个用户是否购买了这个产品。同时,我们还想让用户只需单击一个链接就能启动查询并确定是否被允许下载文件。 这些功能的确非常令人向往。
内容导航九、控制下载
下面,我们开始讲述如何编写一个用于某些文件请求的处理程序,以及该处理程序的安装方法。我们的处理程序的功能很简单,它只是将请求重定向到其他地方而已。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”。此外,我们还要访问请求的产品号码,代码如下所示:
Code highlighting produced by Actipro CodeHighlighter (freeware)
context.Request.QueryString["Product"]
这样,我们就取得了产品号码和用户名。 有了这两者,我们就可以访问UserProducts表并确定这个用户是否购买过这个产品。此外,这个表还存储有该产品的文件名。
既然有了用户名和产品号码,并通过它们确定除了用户购买情况。如果该用户没有购买相应的产品,我们就将其重定向到前面的处理程序,并返回一个访问拒绝页面。为简洁起见,我们将其重定向到一个告知他们还没有购买过此产品的页面,并告知如何进行购买。
如果确定该用户购买了这个产品,可以通过ProductFileName字段了解该用户可以查看哪些文件。这里,我们没有存储完整的路径,只是存储了文件名。如果需要,我们可以从web.config中的设置来获得该文件夹,所以最终获得了完整的文件路径和名称,并授权下载。 下面我们通过称为StartDownload方法来完成此任务:
Code highlighting produced by Actipro CodeHighlighter (freeware)
privatevoid 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);
}