使用HttpHandler实现图片验证码
打开VS,添加一般处理程序(.ashx)。默认已经实现了IHttpHandler里的ProcessRequest方法和IsReusable属性,只需改变ProcessRequest里的方法即可。
(注:在此引用的是袁老师和张老师的例子,写出来呢,主要是学习)
袁老师:http://www.cnblogs.com/xdesigner/archive/2008/06/04/1213496.html
如果对验证码原理还不是很清楚的,请看看袁老师的链接。
张老师:http://www.cnblogs.com/JimmyZhang/archive/2007/09/15/894124.html
//方法一:
<%@ WebHandler Language="C#" class="Handler" %>
using System;
using System.Web;
using System.Web.SessionState;
using System.Drawing;
using System.Text;
using System.Drawing.Imaging;
public class Handler : IHttpHandler, IRequiresSessionState
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "image/gif";
//建立Bitmat对象,绘图
Bitmap basemap = new Bitmap(200, 60);
Graphics graph = Graphics.FromImage(basemap);
graph.FillRectangle(new SolidBrush(Color.White), 0, 0, 200, 60);
Font font = new Font(FontFamily.GenericSansSerif, 48, FontStyle.Bold, GraphicsUnit.Pixel);
Random r = new Random();
string letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
string letter;
StringBuilder s = new StringBuilder();
//添加随机的五个字母
for (int i = 0; i < 5; i++)
{
letter = letters.Substring(r.Next(0, letters.Length - 1), 1);
s.Append(letter);
graph.DrawString(letter, font, new SolidBrush(Color.Black), i * 38, r.Next(0, 15));
}
//混淆背景
Pen linePen = new Pen(new SolidBrush(Color.Black), 2);
for (int i = 0; i < 6; i++)
{
graph.DrawLine(linePen, new Point(r.Next(0, 199), r.Next(0, 59)), new Point(r.Next(0, 199), r.Next(0, 59)));
}
//将图片保存到输出流中
basemap.Save(context.Response.OutputStream, ImageFormat.Gif);
context.Session["CheckCode"] = s.ToString();//如果没有实现IRequiresSessionState,则这里会出错,也无法生成图片
context.Response.End();
}
public bool IsReusable
{
get
{
return false;
}
}
}
添加测试页面:
前台:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!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 runat="server">
<title>无标题页</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<p align="center">
<font face="宋体" size="6">ASP.NET验证码测试页面</font></p>
<font face="宋体">验证码:
<asp:TextBox ID="txtCheckCode" runat="server" Width="224px"></asp:TextBox>
<img src="Handler.ashx" alt="图片验证码" ondblclick="this.src = 'Handler.ashx?flag=' + Math.random() "
style="border: 2px;" />
<!--
这里的 ondblclick 代码中采用一个毫无意义的flag参数可有效的防止浏览器缓存图片
使得显示的验证码图片一定是最新的图片
-->
<span>看不清楚,双击图片换一张。</span>
</font>
<p>
<asp:Button ID="cmdOK" runat="server" Text="点击得到上一个验证码" OnClick="cmdOK_Click"></asp:Button>
</p>
<asp:Label ID="lblResult" runat="server"></asp:Label>
</div>
</form>
</body>
</html>
后台:
using System;
using System.Data;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{}
protected void cmdOK_Click(object sender, EventArgs e)
{
if (System.Web.HttpContext.Current.Session["CheckCode"] != null)
{
lblResult.Text = System.Web.HttpContext.Current.Session["CheckCode"] as string;
}
}
}
结果:
//方法二:
<%@ WebHandler Language="C#" class="Handler" %>
using System;
using System.Web;
using System.Web.SessionState;
using System.Drawing;
using System.Text;
using System.Drawing.Imaging;
public class Handler : IHttpHandler, IRequiresSessionState
{
public void ProcessRequest(HttpContext context)
{
// 创建一个包含随机内容的验证码文本
Random rand = new Random();
int len = rand.Next(4, 6);
char[] chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
StringBuilder myStr = new StringBuilder();
for (int iCount = 0; iCount < len; iCount++)
{
myStr.Append(chars[rand.Next(chars.Length)]);
}
string text = myStr.ToString();
Size ImageSize = Size.Empty;
Font myFont = new Font("MS Sans Serif", 20);
// 计算验证码图片大小
using (Bitmap bmp = new Bitmap(10, 10))
{
using (Graphics g = Graphics.FromImage(bmp))
{
SizeF size = g.MeasureString(text, myFont, 10000);
ImageSize.Width = (int)size.Width + 1;
ImageSize.Height = (int)size.Height + 1;
}
}
// 创建验证码图片
using (Bitmap bmp = new Bitmap(ImageSize.Width, ImageSize.Height))
{
// 绘制验证码文本
using (Graphics g = Graphics.FromImage(bmp))
{
g.Clear(Color.White);
using (StringFormat f = new StringFormat())
{
f.Alignment = StringAlignment.Near;
f.LineAlignment = StringAlignment.Center;
f.FormatFlags = StringFormatFlags.NoWrap;
g.DrawString(
text,
myFont,
Brushes.Black,
new RectangleF(
0,
0,
ImageSize.Width,
ImageSize.Height),
f);
}
}
// 制造噪声 杂点面积占图片面积的 30%
int num = ImageSize.Width * ImageSize.Height * 30 / 100;
for (int iCount = 0; iCount < num; iCount++)
{
// 在随机的位置使用随机的颜色设置图片的像素
int x = rand.Next(ImageSize.Width);
int y = rand.Next(ImageSize.Height);
int r = rand.Next(255);
int g = rand.Next(255);
int b = rand.Next(255);
Color c = Color.FromArgb(r, g, b);
bmp.SetPixel(x, y, c);
}
// 输出图片
System.IO.MemoryStream ms = new System.IO.MemoryStream();
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Gif);
context.Response.ContentType = "image/Gif";
context.Session["CheckCode"] = text;
ms.WriteTo(context.Response.OutputStream);
ms.Close();
}
myFont.Dispose();
}
public bool IsReusable
{
get
{
return false;
}
}
}
测试页面同上。
注:从本质上讲,两种方法是一样的,在此只是让自己多明白理解而已。