其思路如下:获取用户访问下载资源之前的前导页,检查其主机部分是不是与当前主机在同一域名下,如果是则通过正常途径下载的,如果不是,则是通过外部链接下载的。
在asp.net中可以通过HttpRequest的UrlReferrer属性拉获取客户端上次请求的URL信息,用户就是根据上次的URL地址跳转到当前URL地址的。在IHttpHandler的ProcessRequest(HttpContent content)方法中传入了一个HttpContent类的实例,通过这个HttpContent类得实例就能得到当前特定HTTP请求的上下文信息,其中就有Request属性,这个Request属性就是HttpRequest类的实例,通过HttpRequest类的实例的UrlReferrer属性就能知道客户端当前请求的前导页,客户端就是通过前导页连接当前请求的。
<location path="download"> <system.web> <httpHandlers> <add verb="*" path="*.*" type="DownloadHandlerReferrer"/> </httpHandlers> </system.web> </location>
using System;using System.IO;using System.Web;
/// <summary>/// 说明:DownloadHandlerReferrer是一个防盗链的类,它可以防止本站资源被别的网站盗用/// </summary>public class DownloadHandlerReferrer:IHttpHandler{ public DownloadHandlerReferrer() { }
#region IHttpHandler 成员 /// <summary> /// 指示IHttpHandler 实例是否可再次使用 /// </summary> public bool IsReusable { get { return true; } } /// <summary> /// 处理请求的方法 /// </summary> /// <param name="context">它提供对用于为 HTTP 请求提供服务的内部服务器对象(如 Request、Response、Session 和 Server)的引用。</param> public void ProcessRequest(HttpContext context) { HttpRequest request=context.Request; HttpResponse response=context.Response; Uri referrerUri = request.UrlReferrer;//获取下载之前访问的那个页面的uri Uri currentUri = request.Url; string path = request.PhysicalPath;//获取客户端请求的文件的物理地址 if (referrerUri == null)//没有前导页,直接访问下载页 { //输出提示,可以根据自身要求完善此处代码 response.Write("<br>请不要盗链本站资源,请从首页访问。<a href='index.aspx'>首页</a>"); return; } else { if (!File.Exists(path))//如果文件不存在,给出错误提示 { response.Write("请求的文件不存在,请从首页访问。<a href='index.aspx'>首页</a>"); return; } else { #region 判断前导页是否是我们的介绍页面 string referrerPage = referrerUri.LocalPath.Substring(referrerUri.LocalPath.LastIndexOf('/') + 1); if (referrerPage.StartsWith("Download.aspx"))//如果前导页是我们的介绍页面 { //用户是通过正常路径访问的,向用户提供下载文件 //实际情况是根据id从数据库找到文件的物理路径,然后输出 //为了简单代码,仅仅演示流程,这里我直接输出了文件 //获取请求的物理文件路径 WriteFile(path,response); } else { //输出提示,可以根据自身要求完善此处代码 response.Write("referrerPage="+referrerPage+"请不要盗链本站资源,请从首页访问。<a href='index.aspx'>首页</a>"); } #endregion } } } /// <summary> /// 输出文件内容 /// </summary> /// <param name="filePath">带全路径的文件名</param> private void WriteFile(string filePath,HttpResponse response) { //注意这里rar文件的ContentType是application/octet-stream //不同格式文件的contentType有可能不同 string extension=Path.GetExtension(filePath); //设置ContentType属性 response.ContentType =GetMimeType( extension); //获取不带路径的文件名 string fileName = System.IO.Path.GetFileName(filePath); //通过下面的设置保证会在用户浏览器出现下载提示而不是在当前浏览器打开 //Content-Disposition:文件内容描述 //attachment:表示作为附件发送到客户端,客户端将单独打开此文件 //filename:发送到客户端文件的文件名 response.AddHeader("Content-Disposition", "attachment;filename=" + fileName); response.WriteFile(filePath); }
#endregion
/// <summary> /// 根据文件后缀来获取MIME类型字符串 /// </summary> /// <param name="extension">文件后缀</param> /// <returns></returns> public static string GetMimeType(string extension) { string mime = string.Empty; extension = extension.ToLower(); switch (extension) { case ".avi": mime = "video/x-msvideo"; break; case ".bin": mime = "application/octet-stream"; break; case ".exe": mime = "application/octet-stream"; break; case ".dll": mime = "application/octet-stream"; break; case ".class": mime = "application/octet-stream"; break; case ".csv": mime = "text/comma-separated-values"; break; case ".css": mime = "text/css"; break; case ".doc": mime = "application/msword"; break; case ".dot": mime = "application/msword"; break; case ".gz": mime = "application/gzip"; break; case ".gif": mime = "image/gif"; break; case ".jpeg": mime = "image/jpeg"; break; case ".jpg": mime = "image/jpeg"; break; case ".jpe": mime = "image/jpeg"; break; case ".mpeg": mime = "video/mpeg"; break; case ".mpg": mime = "video/mpeg"; break; case ".mpe": mime = "video/mpeg"; break; case ".mp3": mime = "audio/mpeg"; break; case ".pdf": mime = "application/pdf"; break; case ".rar": mime = "application/octet-stream"; break; case ".txt": mime = "text/plain"; break; case ".xls": mime = "application/msexcel"; break; case ".xla": mime = "application/msexcel"; break; case ".z": mime = "application/x-compress"; break; case ".zip": mime = "application/x-zip-compressed"; break; default: break; } return mime; }}