ASP.NET 2的CAPTCHA控件

分享于 

13分钟阅读

Web开发

  繁體

注意:这里控件的新版本在这里是可用的 对控件的所有更新都将发布到 SourceForge.net. 上的项目页上

Sample Image - CaptchaNET_2.gif

介绍

CAPTCHA是"完全自动化的public 图灵测试来区分计算机和人类"的缩写,它是防止计算机程序向Web服务器发送自动请求的最常用技术。 这些可以是元搜索搜索引擎,在登录页面进行字典攻击,或者使用邮件服务器发送垃圾邮件。 你可以能在 Google register 页面上看到了可以用性检查,或者在 Yahoo,或者它的他大型网站上看到了验证码图像。

使用验证器图像文章( ) 编写的第一个CAPTCHA图像生成器是。 之后,我阅读了挑战文章,并对我的代码做了许多更改。 这里控件中使用的代码基于MSDN项目,但某些部分未更改。

使用指导

  • Captcha.ascx 是控制文件。 加载时,它调用 SetCaptcha() 方法。 这里方法使用其他类完成所需的所有操作。
  • RandomText 类生成加密的强随机文本。
  • RNG 类生成加密的强随机数。
  • CaptchaImage 类创建图像。
  • Encryptor 类用于加密和解密。
  • Captcha.ashx 返回图像。

我们将在本文后面讨论其中的一些。

控件

控制代码的主要方法是 SetCaptcha(),每当需要更改图片或者加载它时,它都是执行的。

privatevoid SetCaptcha()
{
 // Set imagestring s = RandomText.Generate();
 // Encryptstring ens = Encryptor.Encrypt(s, "srgerg$%^bg",
 Convert.FromBase64String("srfjuoxp"));
 // Save to session Session["captcha"] = s.ToLower();
 // Set URL imgCaptcha.ImageUrl = "~/Captcha.ashx?w=305&h=92&c=" +
 ens + "&bc=" + color;
}

这使用加密密钥加密随机文本,该密钥在这里代码中硬编码。 为了防止硬编码,可以在数据库中存储这里信息,并在需要时检索。 这里方法还将文本保存到会话中,以便与用户输入进行比较。

要使控件样式为 MATCH,可以使用以下两种属性:

  • 样式
  • 背景颜色

样式属性设置控件样式,背景颜色设置生成图像的背景颜色。

两个事件处理程序处理 SuccessFailure 事件。 我们为这些处理程序使用 delegate

publicdelegatevoid CaptchaEventHandler();

当用户提交表单时,btnSubmit_Click() 验证用户输入。

protectedvoid btnSubmit_Click(object s, EventArgs e)
{
 if (Session["captcha"]!= null && txtCaptcha.Text.ToLower() ==
 Session["captcha"].ToString())
 {
 if (success!= null)
 {
 success();
 }
 }
 else {
 txtCaptcha.Text = "";
 SetCaptcha();
 if (failure!= null)
 {
 failure();
 }
 }
}
RNG类

RNG 类生成加密的强随机数,使用 RNGCryptoServiceProvider 类。

publicstaticclass RNG
{
 privatestatic byte[] randb = new byte[4];
 privatestatic RNGCryptoServiceProvider rand
 = new RNGCryptoServiceProvider();
 publicstaticint Next()
 {
 rand.GetBytes(randb);
 intvalue = BitConverter.ToInt32(randb, 0);
 if (value<0) value = -value;
 returnvalue;
 }
 publicstaticint Next(int max)
 {
 //.. . }
 publicstaticint Next(int min, int max)
 {
 //.. . }
}
RandomText类

为了创建密码强随机文本,我们使用 RNG 类随机选择字符 array 中的每个字符。 这是我第一次在 CryptoPasswordGenerator中看到的非常有用的技术。

publicstaticclass RandomText
{
 publicstaticstring Generate()
 {
 // Generate random textstring s = "";
 char[] chars = "abcdefghijklmnopqrstuvw".ToCharArray() +
 "xyzABCDEFGHIJKLMNOPQRSTUV".ToCharArray() +
 "WXYZ0123456789".ToCharArray();
 int index;
 int lenght = RNG.Next(4, 6);
 for (int i = 0; i < lenght; i++)
 {
 index = RNG.Next(chars.Length - 1);
 s += chars[index].ToString();
 }
 return s;
 }
}
CaptchaImage类

这是我们控制的核心。 它获取图像文本。尺寸和背景颜色,并生成图像。

主要方法是 GenerateImage(),它使用我们提供的信息生成图像。

privatevoid GenerateImage()
{
 // Create a new 32-bit bitmap image. Bitmap bitmap = new Bitmap(this.width, this.height,
 PixelFormat.Format32bppArgb);
 // Create a graphics object for drawing. Graphics g = Graphics.FromImage(bitmap);
 Rectangle rect = new Rectangle(0, 0, this.width, this.height);
 g.SmoothingMode = SmoothingMode.AntiAlias;
 // Fill backgroundusing (SolidBrush b = new SolidBrush(bc))
 {
 g.FillRectangle(b, rect);
 }

首先,声明 BitmapGraphics 对象,以及它的维度与 Bitmap 对象相同的Rectangle。 然后,使用 SolidBrush,我们填充背景。

现在,我们需要设置 font 大小以适应图像。 font 族是从 fonts 族集合随机选择的。

// Set up the text font.int emSize = (int)(this.width * 2/text.Length);
FontFamily family = fonts[RNG.Next(fonts.Length - 1)];
Font font = new Font(family, emSize);// Adjust the font size until// the text fits within the image.SizeF measured = new SizeF(0, 0);
SizeF workingSize = new SizeF(this.width, this.height);while (emSize >2 &&
 (measured = g.MeasureString(text, font)).Width
 > workingSize.Width || measured.Height
 > workingSize.Height)
{
 font.Dispose();
 font = new Font(family, emSize -= 2);
}

通过将图像宽度乘以 2,然后将它的除以文本长度来计算 font的大小。 在大多数情况下,它工作得很好;例如当文本长度为 4且宽度为 8像素时,font 大小将为 4. 但是如果文本长度为 1,则 font 大小为 16. 此外,当图像 height 太短时,文本将不适合图像。 当计算大小小于 2时,我们可以确保它适合于图像,但是当图像 height 非常短时,我们不会注意。 但是当它大于 2时,我们必须确保文本符合图像。 我们通过获取选定的font 和大小的文本需要来获取 widthheight。 如果 width 或者 height 不适合,那么我们将缩小大小并重新检查,直到它适合。

下一步是添加文本。 它是使用 GraphicsPath 对象完成的。

GraphicsPath path = new GraphicsPath();
path.AddString(this.text, font.FontFamily,
 (int)font.Style, font.Size, rect, format);

最重要的部分是着色和扭曲文本。 我们使用RGB代码设置文本颜色,每个颜色使用 0和 255之间的随机值。 随机生成一个随机颜色。 现在,我们必须检查颜色在背景颜色中是否可见。 它通过计算文本颜色 R 通道与背景颜色 R 通道之间的差异来完成。 如果小于 20,我们将重新生成 R 通道值。

// Set font color to a color that is visible within background colorint bcR = Convert.ToInt32(bc.R);int red = random.Next(256), green = random.Next(256), blue =
 random.Next(256);// This prevents font color from being near the bg colorwhile (red >= bcR && red - 20< bcR ||
 red < bcR && red + 20> bcR)
{
 red = random.Next(0, 255);
}
SolidBrush sBrush = new SolidBrush(Color.FromArgb(red, green, blue));
g.FillPath(sBrush, path);

最后,我们通过改变像素颜色来扭曲图像。 对于每个像素,我们从原始图片( 我们不改变的Bitmap 对象) 中选择一个随机图片,并为它设置一个随机像素颜色。 因为 distort 是随机的我们可以看到不同的变形。

// Iterate over every pixeldouble distort = random.Next(5, 20) * (random.Next(10) == 1? 1 : -1);// Copy the image so that we're always using the original for// source colorusing (Bitmap copy = (Bitmap)bitmap.Clone())
{
 for (int y = 0; y < height; y++)
 {
 for (int x = 0; x < width; x++)
 {
 // Adds a simple waveint newX =
 (int)(x + (distort * Math.Sin(Math.PI * y/84.0)));
 int newY =
 (int)(y + (distort * Math.Cos(Math.PI * x/44.0)));
 if (newX <0 || newX >= width)
 newX = 0;
 if (newY <0 || newY >= height)
 newY = 0;
 bitmap.SetPixel(x, y,
 copy.GetPixel(newX, newY));
 }
 }
}
Captcha.ashx

这个HTTP处理程序获取创建 CAPTCHA 映像所需的信息,并返回一个。 注意,这里处理程序接收加密文本并具有解密它的密钥。

publicclass Captcha : IHttpHandler
{
 publicvoid ProcessRequest (HttpContext context) {
 context.Response.ContentType = "image/jpeg";
 context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
 context.Response.BufferOutput = false;
 // Get textstring s = "No Text";
 if (context.Request.QueryString["c"]!= null &&
 context.Request.QueryString["c"]!= "")
 {
 string enc = context.Request.QueryString["c"].ToString();
 // space was replaced with + to prevent error enc = enc.Replace("", "+");
 try {
 s = Encryptor.Decrypt(enc, "srgerg$%^bg",
 Convert.FromBase64String("srfjuoxp"));
 }
 catch { }
 }
 // Get dimensionsint w = 120;
 int h = 50;
 // Widthif (context.Request.QueryString["w"]!= null &&
 context.Request.QueryString["w"]!= "")
 {
 try {
 w = Convert.ToInt32(context.Request.QueryString["w"]);
 }
 catch { }
 }
 // Heightif (context.Request.QueryString["h"]!= null &&
 context.Request.QueryString["h"]!= "")
 {
 try {
 h = Convert.ToInt32(context.Request.QueryString["h"]);
 }
 catch { }
 }
 // Color Color Bc = Color.White;
 if (context.Request.QueryString["bc"]!= null &&
 context.Request.QueryString["bc"]!= "")
 {
 try {
 string bc = context.Request.QueryString["bc"].
 ToString().Insert(0, "#");
 Bc = ColorTranslator.FromHtml(bc);
 }
 catch { }
 }
 // Generate image CaptchaImage ci = new CaptchaImage(s, Bc, w, h);
 // Return ci.Image.Save(context.Response.OutputStream, ImageFormat.Jpeg);
 // Dispose ci.Dispose();
 }
 publicbool IsReusable
 {
 get {
 returntrue;
 }
 }
}

关于此类,只需要注意两点:

  • 由于在URL中,'+'表示空格,我们用'+'替换空格( 用于加密文本)。
  • 在URL中使用 # 会导致问题。 我们不使用颜色值发送 #。 例如当颜色为 #ffffff, 时,我们发送ffffff然后在处理程序中添加 #。

摘要

当控件加载时,它执行 SetCaptcha() 方法。 RandomText 类生成一个随机文本,我们将文本保存到 Session 对象并对它的进行加密。 然后,该方法使用维度。加密文本和背景颜色信息生成图像 URL。

你可能会看到在源代码中使用这里控件的示例。


控制  asp  asp-net  cap  验证码  
相关文章