今天简单的做下HttpHandler的练习:只有登录用户才能下载images下地图片文件(Session中标识是否登录),如果用户没有登录则首先重定向到登录界面让用户登录,用户登录成功则跳转到下载列表页面,下载链接固定写好即可。如果登录用户是普通用户则在图片左上角加上“免费用试用”的字样。
1.首先建立名为UserAuthority的数据库,然后新建名为T_Users的表,如下所示
Level字段是记录用户的下载权限(”0”为免费用户和“1“为收费用户)。ErrorTimes为记录用户错误登录次数。LastErrorTimes则为记录用户错误登录的时间(如果错误登录次数过多则会限制用户登录,防止恶意用户不断进行登录)
再进行操作之前,我现在T_Users表里录入些数据,如下:
2.创建名为DataSetUser的强类型DataSet,然后将表T_Users拖到此文件里面
其中,需要建立查询使用的SQL语句
(GetDataByID(@ID) :SELECT ID, UserName, Password, [Level], ErrorTimes, LastErrorTimes FROM dbo.T_Users
where ID=@ID
,GetDataByUserName :SELECT ID, UserName, Password, [Level], ErrorTimes, LastErrorTimes FROM dbo.T_Users
where UserName=@UserName
,IncErrorTimesById:Update T_Users set ErrorTimes=IsNULL(ErrorTimes,0)+1,LastErrorTimes=getDate() whereID=@ID
ResetErrorTimesById):UPDATE T_Users set ErrorTimes=0 where ID=@ID
3.建立所需页面。
(1).Login.aspx
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using 用户权限下载.DAL.DataSetUserTableAdapters;
namespace 用户权限下载
{
public partial class Login : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
try
{
T_UsersTableAdapter adapter = new T_UsersTableAdapter();
var data = adapter.GetDataByUserName(TextBox1.Text);
if (data.Count <= 0)
{
LabelErrorMsg.Text = "用户名不存在!";
LabelErrorMsg.Visible = true;
}
var user = data.Single();//linq 时的Single方法,返回唯一一条数据,如果数据为0或者多条,则抛出异常,把程序的错误扼杀在摇篮中
if (!user.IsErrorTimesNull() && !user.IsLastErrorTimesNull())
{
double timeSpan = (DateTime.Now - user.LastErrorTimes).TotalMinutes;//计算当前时间和上次时间之间的差得分钟数
if (user.ErrorTimes > 5 && timeSpan < 30)
{
LabelErrorMsg.Text = "您的输入错误次数过多,请再30分钟之后再尝试登录";//一旦被锁定就不告诉访问者密码是对还是错
LabelErrorMsg.Visible = true;
return;
}
}
if (user.Password == TextBox2.Text)
{
Session["IsLoginornot"] = true;
Session["UserID"] = user.ID;
adapter.ResetErrorTimesById(user.ID);
string verCode = Session["Code"].ToString();
LabelErrorMsg.Visible = false;
if (verCode != TextBox3.Text)
{
LabelVerCode.Text = "验证码错误";
LabelVerCode.Visible = true;
// return;
}
else
{
Response.Redirect("DownLoadList.htm");
}
Response.Redirect("DownLoadList.htm");
}
else
{
//int errorTimes=user.ErrorTimes+1;//可直接写到强类型DataSet那里
LabelErrorMsg.Text = "密码错误,请重新输入";//注意数据库值为null的问题
adapter.IncErrorTimesById(user.ID);//增加防暴力破解,重复错误五次,就锁定账户半个小时(错误次数,上次所悟时间)
LabelErrorMsg.Visible= true;
}
}
catch (Exception)
{
}
}
}
(2)图片下载页面 DownloadList.htm
和此页面的HTML代码
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
</head>
<body>
<a href="DownloadPic.ashx?FileName=1.jpg">One</a><br />
<a href="DownloadPic.ashx?FileName=2.jpg">Two</a><br />
<a href="DownloadPic.ashx?FileName=3.jpg">Three</a><br />
</body>
</html>
(3)如果用户还没登录,会提示登录并转到RedirectToLogin.htm
HTML代码:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script type="text/javascript">
var leftSeconds = 4;
setInterval(function () {
if (leftSeconds <= 0) {
window.location.href = "Login.aspx";
}
document.getElementById("leftDiv").innerText = leftSeconds;
leftSeconds--;
}, 1000);
</script>
</head>
<body>
由于您还没登录,不能进行下一步操作,本页面在<div id="leftDiv">0</div>秒后跳转到登录页面<br/>
<a href="Login.aspx">点击这里可以直接跳转到登录页面</a>
</body>
</html>
(4)建立图片下载的过程的代码(动态生成JPEG图片然后弹出对话框让用户下载,文件名为图片名),先建立名为DownloadPic.ashx 的文件
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using 用户权限下载.DAL.DataSetUserTableAdapters;
using System.Drawing;
using System.Drawing.Imaging;
using System.Web.SessionState;
namespace 用户权限下载
{
/// <summary>
/// DownloadPic 的摘要说明
/// </summary>
public class DownloadPic : IHttpHandler, IRequiresSessionState
{
public void ProcessRequest(HttpContext context)
{
if (context.Session["IsLoginornot"] == null)
{
context.Response.Redirect("RedirectToLogin.htm");//跳转到RedirectToLogin页面,3秒后或直接点击进入Login.aspx页面
}
else
{
string filename = context.Request["FileName"];
context.Response.ContentType = "images/JPEG";
string encodeFileName = HttpUtility.UrlEncode(filename);
context.Response.AddHeader("Content-Disposition", string.Format("attachment;filename=\"{0}\"", encodeFileName));
int userId = (int)context.Session["UserID"];
T_UsersTableAdapter adapter = new T_UsersTableAdapter();
var data = adapter.GetDataByID(userId);
var user = data.Single();
if (user.Level == 0)
{
using (Bitmap bitmap = new Bitmap(context.Server.MapPath("images/") + filename))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
g.DrawString("免费用户使用", new Font("宋体", 40), Brushes.Red, 0, 0);
}
bitmap.Save(context.Response.OutputStream, ImageFormat.Jpeg);
}
}
else//收费用户
{
context.Response.WriteFile("images/" + filename);//有攻击漏洞,重复错误5次,就锁定账户半个小时。还有,避免DownloadPic.ashx?FileName=../DownloadPic.ashx.cs 的漏洞
}
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
}
4.增加验证码功能:
VerificationCode
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Drawing;
namespace 用户权限下载
{
/// <summary>
/// VerificationCode 的摘要说明
/// </summary>
public class VerificationCode : IHttpHandler, System.Web.SessionState.IRequiresSessionState
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType="images/JPEG";
using(Bitmap bitmap=new Bitmap(70,35))
{
using(Graphics g=Graphics.FromImage(bitmap))
{
Random rand=new Random();
int code=rand.Next(1000,9999);
string strCode=Convert.ToString(code);
HttpContext.Current.Session["Code"]=strCode;
g.DrawString(strCode,new Font("宋体",20),Brushes.Red,0,0);
bitmap.Save(context.Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg);
}
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
}