2010-12-01 99 views
4

我想知道如何在有限的时间内为我的文件生成临时下载地址。我知道这不是最好的做法,可能使用HttpHandlers是根据http://www.devx.com/codemag/Article/34535/1954
要走的路但我很想知道如何使用urlrewriting生成文件名使用GUID或一些其他隐秘的命名技术,并使其可用时间有限。
我会很感激,如果有人指出我有关它的好文章。与ASP.NET临时文件下载链接

+0

你使用ASP.NET MVC吗? – Aliostad 2010-12-01 11:45:11

+0

不,我使用Webforms。 – Kamyar 2010-12-01 11:46:36

+1

在这种情况下使用url重写会有什么收获?为什么GUID不能在查询字符串中? – 2010-12-01 11:47:20

回答

6

那么首先你需要某种形式的标识符。你建议一个GUID,这很容易完成,Guid.NewGuid().ToString("n")给你这样一个标识符。

你谈论URI重写,但这真的只是一点点抛光。您当然可以做一些重写,将/myFiles/a948ec43e5b743548fd9a77c462b953e转换为/myFiles/download.aspx?id=a948ec43e5b743548fd9a77c462b953e或甚至(在查看查表后)转换为myFiles/download.aspx?id=3myFiles/download.aspx?fileName=myNewDownload.pdf。这与任何其他URI重写任务相同,所以现在让我们忽略它并假设我们有一个请求进入/myFiles/download.aspx?id=a948ec43e5b743548fd9a77c462b953e,无论这是否由于重写。

好的。您有一个标识符,您需要将其与三件事情匹配:流,内容类型和有效日期。

您可以将所有这些存储在文件系统中,全部存储在数据库中或数据库中的详细信息中,包括将流存储为文件在文件系统中的路径。

可以说,它的名字一样存储在文件系统:

a948ec43e5b743548fd9a77c462b953e.application_pdf和a5d360178ec14e97abd556ed4b7709cf.text_plain,我们没有使用普通的windows文件扩展名的charset = UTF-8

注意,所以我们很好地处理了上传机器与您的服务器有不同绑定的情况。

在a948ec43e5b743548fd9a77c462b953e是我们先来看一下创建日期,如果它是很久以前(该文件已到期),我们发送一个错误消息,说明该文件中的410 GONE头所需的项目的情况下,已过期(我们也可以删除该文件以清理使用情况 - 或者截断它,以便它保留该文件曾经存在的记录,但是是0bytes的存储空间)。

否则,我们将Response.ContentType设置为“application/pdf”,然后Response.TransmitFile发送文件。

如果我们以不同于文件的方式存储流,我们希望以小块(4096很好地匹配系统其他部分中的其他缓冲区)发送它,并且在非常特殊的情况下定期拨打大号Response.Flush()以防止内存问题。

这是您的基本系统完成。好处包括存储原始文件名并将其发送到内容处理标题中,并遵守范围请求,以便用户可以恢复失败的下载,而不必从头开始。

所有这些都与用于确保只有正确的人拥有该文件的任何身份验证非常正交 - 您可以将它与任何类型的登录系统配合使用,也可以将其保留为公开但时间有限。

3

无论你使用的ASP.NET框架如何,我都会支持一个加密的令牌,它加密一个文件ID(我假设你有)和一个DateTime,它可以在服务器端解密并根据它的时间戳进行验证。

下面是一个简单的实现:

public static string GetDownloadToken(int fileId) 
    { 
     byte[] idbytes = BitConverter.GetBytes(fileId); // 4 bytes 
     byte[] dateTimeBytes = BitConverter.GetBytes(DateTime.Now.ToBinary()); // 8 bytes 
     byte[] buffer = new byte[16]; // minimum for an encryption block 
     string password = "password"; 

     byte[] passwordBytes = Encoding.ASCII.GetBytes(password); 
     Array.Copy(idbytes, 0, buffer, 0, idbytes.Length); 
     Array.Copy(dateTimeBytes, 0, buffer, idbytes.Length, dateTimeBytes.Length); 
     byte[] encryptedBuffer = new byte[256]; 
     using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider()) 
     { 
      int count = sha1.TransformBlock(buffer, 0, buffer.Length, encryptedBuffer, 0); 
      return Convert.ToBase64String(encryptedBuffer, 0, count); 
     } 
    }