文件结构图如下:
Default.aspx //此页面只有两个简单的下载链接
<div>
<a href="download/download.rar">下载download.rar</a>
<a href="download/readme.txt">下载readme.txt</a>
</div>
Default.aspx.cs //因为在此使用的session验证,所以只是在Page_Load事件中定义了一个session
protected void Page_Load(object sender, EventArgs e)
{
Session["visited"] = true;//注意在HttpHandler中将检查这个值是否为空来判断用户是否访问过这个页面
}
DownloadHandlerReferrer.cs //主体部分
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.IO;
/// <summary>
/// 用于实现防盗链的HttpHandler,本实例中是通过Session中来判断用户是否非本站链接下载本站文件
/// 主要要访问Session的话,我们的自定义类还必须实现System.Web.SessionState.IRequiresSessionState接口
/// </summary>
public class DownloadHandlerReferrer : IHttpHandler, System.Web.SessionState.IRequiresSessionState
{
public DownloadHandlerReferrer()
{
}
#region IHttpHandler 成员
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
HttpRequest request = context.Request;
HttpResponse response = context.Response;
string requestFile = request.PhysicalPath;
HttpSessionState session = context.Session;
//注意这里ForbiddenThief同时实现了两个接口IHttpHandler及IRequiresSessionState,要想访问Session必须要实现后一个接口
if (session["visited"] == null)//如果通过指定下面中的链接下载,就会设置Session["visited"]的值
{
response.Write("请不要盗链本站资源,请从首页访问。");
}
else//如果Session["visited"]为空表明用户没有通过正常途径访问本页面,即为盗链网站链接过来的
{
if (File.Exists(requestFile))
{
WriteFile(requestFile, response);
}
else
{
response.Write("你下载的文件不存在。");
}
session.Remove("visited");//清除Session,保证用户下次下载还需要经过相关页面跳转
}
}
/// <summary>
/// 向客户端输出文件
/// </summary>
/// <param name="filePath">文件的完整物理路径</param>
/// <param name="response">服务器响应对象的实例</param>
private void WriteFile(string filePath,HttpResponse response)
{
string extension = Path.GetExtension(filePath).ToLower();
string contentType=GetMimeType(extension);
response.Clear();
response.ContentType = contentType;
string fileName = System.IO.Path.GetFileName(filePath);
//下面的方法保证在客户端出现下载对话框而不是在浏览器中打开
response.AddHeader("Content-Disposition", "attachment;filename=" + fileName);
response.WriteFile(filePath);
}
/// <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;
}
#endregion
}
最后在web.config中的<configuration>节点下需要添加如下配置节:
<!--指定需操作的文件夹-->
<location path="download">
<system.web>
<httpHandlers>
<!--type="DownloadHandlerReferrer" 指所定要操作的类,path="*.*" 指文件类型-->
<add verb="*" path="*.*" type="DownloadHandlerReferrer"/>
</httpHandlers>
</system.web>
</location>