共享一款ASP.NET验证码控件(附详细用法)转

在最初决定搞Web开发的时候就思考过网站上的验证码是怎么实现的,后来在一些专业书籍上也看过一些介绍,但并没有自己去实现过。在www.51aspx.com上下载了一些源码研究过,感觉都不是很满意,一直都想找一个可以直接从工具箱拖出来用的验证码控件,点击可刷新换图的那种,那样多方便啊

 

   最近在完善我的毕业设计——ASP.NET(C#)实现的三层构架的二手交易系统,觉得有必要加上验证码,这样网站的安全性会提升一些。于是利用百度、谷歌反复搜索,终于找到了一款比较牛叉的验证码控件。原作者不详,这里附上一个地址>>>。程序我做了一些小小的修改。

 

   按原文所说的操作,根本编译不了。原文的用法可以查看上面的链接地址,这里我贴出我自己的用法。我将两个类整合到一个.cs文件中了(这里命名为AuthCode.cs),程序如下:(下半部分,在后一篇文章“[原创]共享一款ASP.NET验证码控件(附详细用法)中”里已全部列出)

 

 

using System;
using System.Collections.Generic;
usingSystem.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI.WebControls;
usingSystem.Web.UI;
usingSystem.Web.SessionState;
using System.Drawing;
using System.IO;

namespaceAuthCode
{
[ToolboxData(
"<{0}:AuthCoderunat=server></{0}:AuthCode>")]
public class AuthCode: WebControl
{
/// 〈summary>
/// 获得验证码的值
/// 〈/summary>
/// 〈returns>验证码〈/returns>
public string GetValue()
{
return HttpContext.Current.Session["value"].ToString();
}


[Bindable(
true)]
[Category(
"Appearance")]
[Description(
"验证码字符长度")]
[DefaultValue(
"ss")]
[Localizable(
true)]
//长度
internal static int mySize;

public int MySize
{
get { return AuthCode.mySize; }
set
{
AuthCode.mySize
=value;
}
}

public AuthCode()
:
base(HtmlTextWriterTag.Img)//重写父类的构造(输出流的HTML标记)
{ }


protected override void AddAttributesToRender(HtmlTextWriter writer)
{
base.AddAttributesToRender(writer);//将要输出的的HTML标签的属性和样式添加到指定的HtmlTextWriter中
writer.AddStyleAttribute(HtmlTextWriterStyle.Cursor,"pointer");//添加样式

writer.AddAttribute(
"onclick","this.src='img.jd?id='+Math.random()");//添加jsVerifyImg.jd
writer.AddAttribute(HtmlTextWriterAttribute.Src,"img.jd");
writer.AddAttribute(
"alt","点击刷新");
}

}


public class AuthCodeHttpHander : IHttpHandler,IRequiresSessionState
{
/// <summary>
/// 返回验证码字符
/// </summary>
/// <paramname="codeCount">验证码长度</param>
/// <returns></returns>
private string GetRandomNumberString(int codeCount)
{
string strChoice = "2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,T,U,V,W,X,Y,Z";
string[] strResult = strChoice.Split(new Char[]{ ','});
string strReturn = "";
Random rnd
=new Random();
for (inti = 0; i< codeCount; i++)
{
int j =rnd.Next(strResult.Length);//随机数不能大于数组的长度
strReturn = strReturn + strResult[j].ToString();
}
return strReturn;
}

private Color GetColor()
{
return Color.Black;
}

private Bitmap CreateImage(string str_AuthCode)
{
int width =str_AuthCode.Length* 13;
int height = 20;
Random rad
=new Random();
Bitmap bmp
=new Bitmap(width, height);
Graphics grp
=Graphics.FromImage(bmp);// 在图片上绘制图形
grp.Clear(Color.White);//填充bmp的背景色
grp.DrawRectangle(newPen(Color.Red, 1),0, 0,width - 1,height - 1);//绘制边框
int num =width * height;
for (inti = 0; i< num; i+=3)//在图片的指定坐标上画上有颜色的圆点
{
int x =rad.Next(width);
int y =rad.Next(height);
int r =rad.Next(255);
int g =rad.Next(255);
int b =rad.Next(255);
Color c
= Color.FromArgb(r, g, b);
bmp.SetPixel(x, y, c);
//在图片的指定坐标上画上有颜色的圆点
}

Font f
= new Font("宋体",12, FontStyle.Bold);//定义字体
Brush br = new SolidBrush(Color.Black);//定义画笔的颜色及字体的颜色
for (inti = 0; i< str_AuthCode.Length; i++)
{
string s =str_AuthCode.Substring(i,1);//单个单个的将字画到图片上
Point p = new Point(i * 12+ rad.Next(3),rad.Next(3) +1);//字体出现的位置(坐标)
grp.DrawString(s, f, br, p);//绘制字符串
}
grp.Dispose();
return bmp;//返回

}

/// <summary>
/// 是否可以处理远程的HTTP请求
/// </summary>
public bool IsReusable
{
get { return true; }
}

/// <summary>
/// 将验证码图片发送给WEB浏览器
/// </summary>
/// <paramname="context"></param>
public void ProcessRequest(HttpContext context)
{
int size =AuthCode.mySize; //Int32.Parse((String)context.Session["Size"]);
MemoryStream ms =new MemoryStream(); // 创建内存流(初始长度为0自动扩充)
string NumStr = GetRandomNumberString(size);// 获得验证码字符
context.Session.Add("value",NumStr);//将验证码字符保存到session里面
Bitmap theBitmap =CreateImage(NumStr);//获得验证码图片
theBitmap.Save(ms,System.Drawing.Imaging.ImageFormat.Jpeg);//将位图写入内存流
context.Response.ClearContent(); //清除缓冲区里的所有内容输出
context.Response.ContentType = "image/jpeg";//需要输出图象信息 要修改HTTP头
context.Response.BinaryWrite(ms.ToArray()); //将内存流写入HTTP输出流
theBitmap.Dispose(); //释放资源
ms.Close();//释放资源
ms.Dispose();//释放资源
context.Response.End();
}

}

}

 

 

   这个自定义控件的源代码在前两篇博文中(应gogo网友的质疑添加的补充说明)。

 

   我是这样使用这个验证码控件的:


   1:修改web.config 文件


    在<system.web></system.web>间加入下面的代码:

   <httpHandlers>
   
     <add verb="*" path="*.jd" type="AuthCode.AuthCodeHttpHander" />
   
</httpHandlers>

    2:“开始”—“运行”—“cmd”,用下面的两条命令编译AuthCode.cs文件为.DLL文件。(AuthCode.cs文件保存在“C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727”目录下)命令如下:

    cdC:\WINDOWS\Microsoft.NET\Framework\v2.0.50727

    csc/target:library AuthCode.cs

   将得到的DLL文件添加到项目的引用中,在“工具箱”中右键点“选择项...”——在.net组件中勾选“AuthCode”(如下图),点确定之后工具箱中就会增加一个AuthCode控件。
 

 

   将这个控件从工具箱中拖到页面里使用。选中拖出的控件,在其属性中设置MySize即验证码的长度为某一正整数。例如设置成4,自动生成的代码如下(还有自动生成的注册这个控件的代码,这里未列出):
 
   <cc1:AuthCode ID="AuthCode1"runat="server" MySize="4"  />
 
   到此,准备工作“基本”完成。(说“基本完成”是因为IIS里漏了一个必要的设置_^)
 
   在.NET2005中通过“文件”—“打开”—“网站”—“本地IIS”打开ASP.NET(C#)的网站项目,能正常运行页面,验证码控件生成的图片显示不了(只显示一个红叉)。 改用“文件系统”的形式打开则可以正常显示。这个问题我思考了好几天,还到一些技术论坛请教过别人,没人帮我解决(依靠别人是不行的)。这里只贴出那个最早的帖子的地址>>>,在编程论坛、编程爱好者上的帖子就不贴出来了。
 
   我每天都试着去解决一下这个问题,终于慢慢找到了问题的症结。
 
   因为是在用IIS调试时出问题的,所以我猜测问题很有可能就出在IIS的某个设置上。
 
   今天偶然发现IIS里有修改HTTP头的设置,而且上面的程序注释中提到了要修改HTTP头,语句如下:
 
    context.Response.ContentType= "image/jpeg";//需要输出图象信息 要修改HTTP头 
 
   同时,web.config 文件中也有对“HTTP头”的设置,设置如下:
 
   <httpHandlers>
   
    <add verb="*" path="*.jd" type="AuthCode.AuthCodeHttpHander" />
   
</httpHandlers>
 
   于是,我到MSDN里找到了一些与<httphandlers>相关的资料,资料如下:
 
   <httpHandlers>设置由应用程序子目录继承。

   <add> 指令按由上而下的顺序进行处理。如果两个或多个<add> 元素指定相同的谓词/路径组合,则最后一个<add> 会重写其他所有元素。

    MicrosoftInternet 信息服务 (IIS) 有自己的 ISAPI映射扩展模型。为使给定应用程序扩展与其处理程序之间的映射生效,该扩展必须在 IIS 中映射为 ASP.NETISAPI。对于自定义扩展等非标准扩展,则必须相应地配置 IIS。
 
   受上面资料的启发,我又仔细翻查了IIS的设置,发现有个“映射”的设置。加上考虑到这个控件实际生成的是一个.jd的文件(没见过的扩展名...),所以我怀疑用IIS调试显示不了这个验证码图片的症结就在这里
 
   我以“<httpHandlers> IIS”为关键字百度了一下,经验证,终于找到了准确有效的设置办法:
 
   通过“程序”—>“管理工具”—>“Internet信息服务”—>选中“默认网站”—>右键点“属性”
 
—>“主目录”—>“配置”—>“映射”—>“添加”来设置: 

   路径为: C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll 

 

    扩展名为:.jd

 

   限制为:GET,HEAD,POST,DEBUG 

 

   去掉“检查文件是否存在”前的勾。(必须去掉这里的“”)

   

   如下图:

 

 

补充:

 

   一般来说,我们只要在IIS控制台中打开目标网站的属性设置窗口,单击其中的“主目录”标签,在该标签设置页面的“应用程序设置”处单击“配置”按钮,在其后界面中单击“添加”按钮,之后就能根据界面提示完成应用程序扩展名映射添加操作了。然而,有的朋友在打开应用程序扩展名添加对话框后,发现其中的“确定”按钮处于灰色不可用状态;并且,朋友通过“浏览”按钮导入了应用程序详细路径,以及设置了对应程序的扩展名后,发现应用程序扩展名添加对话框中的“确定”按钮依然处于灰色不可选状态。

 

 
  要想解决这种故障现象,我们只要将鼠标指针移动到图1界面的“可执行文件件”文本框中并进行单击操作,这样我们就会看到压缩路径此时就会自动失效,同时应用程序扩展名映射添加/编辑对话框中的“确定”按钮也就被自动激活了,一旦发现“确定”按钮处于可点击状态时,我们就能成功完成应用程序扩展映射配置操作了。当然,我们如果知道目标应用程序的详细路径时,可以直接采用手工输入的方法输入目标应用程序的路径信息,并且设置好它的扩展名称,这样一来“确定”按钮就不会失效,我们只要单击“确定”按钮,就能将指定的应用程序扩展名映射添加成功了。以上补充内容的原文地址>>>

 

   完成上面的设置之后,再用“本地IIS”调试,验证码可以正常显示,问题解决,效果如下图。(当然,发布网站也得做这样的设置。)

 

 

   其实我这种使用自定义控件的方法属于非常规的方法,关于怎么创建和使用自定义控件,可以查看这个链接地址>>>>,讲解的很详尽。

 

   另外,上面的这个验证码控件生成的图片效果并不是很清晰(画了太多黑点则会影响验证字符的人为辨别),需要的可以自行修改一下。这个验证码控件的注释很详细,所以理解和修改的难度都不大。在这里我要感谢原作者共享的这个控件,我只是对将这个控件的使用发表了一下自己的看法。

 

   前面主要说明的是怎么引用这个自定义控件以及怎么设置IIS让图片正常显示。

 

   下面是应网友gogo的提问所做的补充(如何取验证码字符串及如何比较):

 

   不区分大小写的话,就将字符串都转换成大写或者小写。例如,与输入字符串的比较(都转换成大写)的方法为(不要在page_Load里引用该验证码字符串):

 

     if(this.AuthCode1.GetValue().ToUpper()!= txtVerify.Text.ToUpper())
    {

         Response.Write("<scriptlanguage='javascript'>alert('验证码输入错误!'</script>");

    }


    这里的AuthCode1是验证码控件实例的ID(前面已经列出过),txtVerify是接受用户输入验证码的TextBox的ID。如:

 

   <asp:TextBox ID="txtVerify"runat="server" Width="81px"BorderStyle="Groove"  

    ForeColor="Black" ToolTip="不区分大小写"></asp:TextBox>

 

 

    用IIS调试,网站项目必需放在IIS主目录里(同时也要建好虚拟目录)。具体的设置请搜索关于IIS用法的相关文章。

 

 

转载自:http://blog.sina.com.cn/xuezhide

posted @ 2010-01-18 04:16  过世许久  阅读(593)  评论(0)    收藏  举报