使用ASP.NET简单的文件下载保护

当涉及从未授权的下载保护文件时,绝大多数文章提供了涉及在Internet信息服务中映射到ASP.NET的常见文件类型(.pdf,.pdf,.txt,.doc等)的解决方案。 但是,通常在共享的托管环境中,你不'有权访问IIS,主办公司不会同意为您提供此类映射,所以你做了什么?

让'首先审视问题首先是更多细节。 在ASP.NET中的表单身份验证仅适用于IIS 6.0中的ASP.NET处理的请求(通常是Windows Server 2003),这意味着非Asp.NET内容绕过ASPNet.dll,并且不受它的影响。让'S表示您在应用程序中有一个名为私有的文件夹。 您设置了Forms身份验证以保护此文件夹,例如以下Web.config段:

<system.web>
  <authentication mode="Forms">
    <forms loginUrl="Private/Login.aspx" defaultUrl="Private/Default.aspx">

      <credentials passwordFormat="Clear">
        <user name="mike" password="test" />

      </credentials>
    </forms>
  </authentication>
</system.web>
<location path="Private">

  <system.web>
    <authorization>
      <deny users="?" />
    </authorization>

  </system.web>
</location>

The URL to your Private folder is http://www.mysite.com/Private.  Any requests for that URL will invoke the default document, which in this case is Private/Default.aspx.  Since that has been protected under Forms Authentication, and since all .aspx files are mapped to aspnet.dll, Forms Authentication kicks in and users who have not already logged in will be redirected to Private/Login.aspx.  Login.aspx contains a straightforward Login Control:

<form id="form1" runat="server">
<div>

  <asp:Login ID="Login1" runat="server" onauthenticate="Login1_Authenticate" />

</div>
</form>

代码背后包含身份验证逻辑:

protected void Login1_Authenticate(object sender, AuthenticateEventArgs e)
{
  string username = Login1.UserName;
  string password = Login1.Password;
  if(FormsAuthentication.Authenticate(username, password))
  {
    FormsAuthentication.RedirectFromLoginPage(username, false);
  }
}


成功验证的用户将被定向到Default.aspx,其中包含可下载文件的链接:

<form id="form1" runat="server">
<div>
<a href="HelloWorld.txt">Click Here to Get File</a>

</div>
</form>

This seems to work, but if a non-authenticated user just enters http://www.mysite.com/Private/HelloWorld.txt into their browser, the file will be served, as ASP.NET is not configured to handle .txt files.  As I mentioned before, the vast majority of articles on this topic show how to map .txt to aspnet.dll within IIS, create an HttpHandler to manage the file access, and then register that handler within the web.config file.  If you do not have access to IIS, there is a simple workaround.  The first thing to do is to move all download files to a location where they cannot be browsed.  Ideally, your web hosting company will have provided you with access to at least one folder above the root folder of your application.  This is ideal, because no one can browse that folder since it is not part of the application itself.  However, if you only have access to the root folder and its contents, there is still at least one other option - App_Data.  Anything placed in App_Data is protected by ASP.NET, and requests for items within it are met with a 403 - Forbidden error message.

移动文件后,您需要一种方法来服务于经过身份验证的用户,而HttPhandler将轻松完成作业。 只需添加...新项目,然后选择通用处理程序。 您应该与一个新文件满足,其中包含一个包含这样的代码的.Ashx扩展名:

public class MyFileHandler : IHttpHandler
{

  public void ProcessRequest(HttpContext context)
  {
    context.Response.ContentType = "text/plain";
    context.Response.Write("Hello World");
  }

  public bool IsReusable
  {
    get
    {
      return false;
    }
  }
}


处理程序包含两种方法 - processRequest和IrReusable。 第一个容纳需要运行以处理当前请求的逻辑,第二个都指示是否可以汇集处理程序并重用其他请求。 为了简单起见,可以根据它留下默认值的默认值。 关于处理程序的点,与其.ashx扩展名的泛型处理程序选项是它已被映射到aspnet.dll,因此它可以参与表单身份验证。 不仅如此,而且它不需要在Web.config文件中注册。现在它只是一个添加一些逻辑来验证用户的问题,并检索它们的文件:

public class MyFileHandler : IHttpHandler

{

  public void ProcessRequest(HttpContext context)
  {
    if (context.User.Identity.IsAuthenticated)
    {
      string filename = context.Request.QueryString["File"];
      //Validate the file name and make sure it is one that the user may access
      context.Response.Buffer = true;
      context.Response.Clear();
      context.Response.AddHeader("content-disposition", "附件; filename=" + filename);
      context.Response.ContentType = "应用/八元门流";

      context.Response.WriteFile("~/App_Data/" + filename);
    }
  }

  public bool IsReusable
  {
    get
    {
      return false;
    }
  }
}

这真的很简单。 在建立当前用户是否已被身份验证后,处理程序检查QueryString for Filename。此时,验证文件名非常重要,以确保用户可以访问它。用户可以将QueryString更改为指向App_Data之上的文件夹,例如根目录,并通过将Web.config求予Web.config。 这将在大多数服务器上抛出异常,因为默认情况下禁用父路径的..//表示父路径。 但是,随着下面提到的几个评论员,情况并非总是如下。

然后该方法只需使用response.wrile()来传递文件。 我已将文件的ContentType设置为 应用/八元门流和内容倾应 附件 上面,它将涵盖任何类型的文件并始终强制保存或打开对话框。 您可能更愿意检查文件扩展名并相应地设置ContentType。 您可能还希望添加一些错误检查逻辑以确保已通过QueryString值,该文件存在等。

但是,如果您未使用框中的FormsAuthentication,则可以在每个页面上检查会话变量,以查看用户是否已登录。 这种情况,您需要知道HttPhandlers默认情况下没有访问会话状态,因此对会话变量的引用将失败。 一个更改就是必需的,这是使您的HttPhandler实现IreadonlySessionState(如果要修改会话变量,则为IredOressSessionState)。 传递给ProcessRequest()方法的HttpContext对象通过其会话属性提供对会话变量的访问。

public class MyFileHandler : IHttpHandler, IReadOnlySessionState

{
 ....
 

 

这只是让一个问题 - 文件名如何进入QueryString?  返回私有/ default.aspx,我们只需修改链接即可指向处理程序:

<form id="form1" runat="server">
<div>

<a href="MyFileHandler.ashx?File=HelloWorld.txt">Click Here to Get File</a>
</div>
</form>

在提供文件之前,我们拥有简单的身份验证检查,而无需在Web.config文件中注册处理程序,或使用IIS设置进行混淆。 如果您正在运行IIS 7.0的服务器上托管,事情很容易。凭借其新的集成管道模型,对您的应用程序进行了简单的更改'S Web.config文件将确保应用程序中的所有内容始终由ASP.NET处理,以便非Asp.NET内容可以参与ASP.NET表单身份验证。  本文 详细信息如何进行更改。