我使用ASP.NET
我需要为用户提供从服务器下载文件的临时链接。
这应该是一个临时链接(页面),在短时间内可用(例如12小时)。我如何生成此链接(或带有链接的临时网页)?
这里是一个相当完整的示例。
首先,一个函数用来创建一个带有秘密盐和过期时间的短十六进制字符串:
public static string MakeExpiryHash(DateTime expiry)
{
const string salt = "some random bytes";
byte[] bytes = Encoding.UTF8.GetBytes(salt + expiry.ToString("s"));
using (var sha = System.Security.Cryptography.SHA1.Create())
return string.Concat(sha.ComputeHash(bytes).Select(b => b.ToString("x2"))).Substring(8);
}
以下是生成一周过期链接的代码片段:
DateTime expires = DateTime.Now + TimeSpan.FromDays(7);
string hash = MakeExpiryHash(expires);
string link = string.Format("http://myhost/Download?exp={0}&k={1}", expires.ToString("s"), hash);
如果提供了有效链接,最终将下载页面发送给文件:
DateTime expires = DateTime.Parse(Request.Params["exp"]);
string hash = MakeExpiryHash(expires);
if (Request.Params["k"] == hash)
{
if (expires < DateTime.UtcNow)
{
// Link has expired
}
else
{
string filename = "<Path to file>";
FileInfo fi = new FileInfo(Server.MapPath(filename));
Response.ContentType = "application/octet-stream";
Response.AddHeader("Content-Disposition", "attachment;filename=" + filename);
Response.AddHeader("Content-Length", fi.Length.ToString());
Response.WriteFile(fi.FullName);
Response.Flush();
}
}
else
{
// Invalid link
}
你应该一定要加上异常处理来捕获错误的请求。
http://example.com/download/document.pdf?token=<token>
这里的关键部分是<token>
。如果您不想涉及数据库,可以加密链接创建时间,将其转换为URL安全的Base64表示,并提供给用户该URL。当请求该URL时,解密token
并将其中存储的日期与当前日期和时间进行比较。
或者,您可以拥有一个单独的DownloadTokens
表,将这些token
(可以是GUID)映射到过期日期。
IHttpHandler
,但这并不是什么大问题。 - Anton Gogolev在查询字符串中给URL添加一个时间戳:
page.aspx?time=2011-06-22T22:12
检查时间戳是否与当前时间匹配。
为了防止用户自己更改时间戳,还需要计算一些秘密哈希值,并将其追加到查询字符串中:
page.aspx?time=2011-06-22T22:12&timehash=4503285032
如果要使用哈希,你可以做一些像日期时间中所有字段求和再对某个质数取模,或者是对时间的字符串表示进行SHA1哈希等操作。这样用户就无法在不知道正确哈希值的情况下更改时间戳。在你的page.aspx页面中,你可以将给定的哈希值与时间戳的哈希值进行比较。
有很多种方法可以实现。
我曾经为一个项目做过的一种方式是生成唯一的密钥,并使用动态下载脚本来流式传输文件。当文件请求被发出时,密钥会被生成并存储在数据库中,同时记录创建时间和所请求的文件。您可以构建一个链接到下载脚本,并传入密钥。从那里开始,很容易跟踪到期时间。
llya
我假设您不需要任何身份验证,安全也不是问题 - 也就是说,如果有人获得了URL,他们也可以下载文件。
个人建议创建一个HttpHandler,然后创建一些唯一的字符串,可以将其附加到URL中。
然后在ProcessRequest void中测试编码参数是否仍然可行(在指定的时间范围内),如果是,则使用BinaryWrite呈现文件;如果不是,则可以使用Response.Write(“已过期”)呈现一些HTML。
类似于:
public class TimeHandler : IHttpHandler, IRequiresSessionState
{
public void ProcessRequest ( HttpContext context )
{
if( this.my_check_has_expired( this.Context.Request.Params["my_token"] ) )
{
// Has Expired
context.Response.Write( "URL Has Expired" );
return;
}
// Render the File
Stream stream = new FileStream( File_Name , FileMode.Open );
/* read the bytes from the file */
byte[] aBytes = new byte[(int)oStream.Length];
stream.Read( aBytes, 0, (int)oStream.Length );
stream.Close( );
// Set Headers
context.Response.AddHeader( "Content-Length", aBytes.Length.ToString( ) );
// ContentType needs to be set also you can force Save As if you require
// Send the buffer
context.Response.BinaryWrite( aBytes );
}
}
接下来,您需要在IIS中设置处理程序,但这取决于您使用的版本有所不同。