驗證碼功能一般是用于防止批量注冊的,不少網站為了防止使用者利用機器人自動注冊、登入、灌水,都采用了驗證碼技術。所謂驗證碼,就是将一串随機産生的數字或字母或符号或文字,生成一幅圖檔, 圖檔裡加上一些幹擾象素(防止OCR),由使用者肉眼識别其中的驗證碼資訊,輸入表單送出網站驗證,驗證成功後才能使用某項功能。
一、驗證碼簡介
驗證碼功能一般是用于防止批量注冊的,不少網站為了防止使用者利用機器人自動注冊、登入、灌水,都采用了驗證碼技術。所謂驗證碼,就是将一串随機産生的數字或字母或符号或文字,生成一幅圖檔, 圖檔裡加上一些幹擾象素(防止OCR),由使用者肉眼識别其中的驗證碼資訊,輸入表單送出網站驗證,驗證成功後才能使用某項功能。
常見的驗證碼有如下幾種:
1、純數字驗證碼,一般為四位随機數字;
2、數字+字母驗證碼,一般從數字(0~9)和字母(A~Z和a~z)中随機抽出幾個字元組成;
3、漢字驗證碼,相對而言,這種驗證碼比較少見一點,實作起來也相對複雜一些,但在不少網站中還是可以看到的;
二、驗證碼的實作
1、純數字驗證碼的實作
純數字驗證碼的實作相對比較簡單,可通過以下兩種方法來實作
(1)使用随機數方式,代碼如下:
private String GetRandomint(int codeCount)
{
Random random = new Random();
string min = "";
string max = "";
for (int i = 0; i < codeCount; i++)
{
min +="1";
max+="9";
}
return (random.Next(Convert.ToInt32(min),Convert.ToInt32(max)).ToString());
}
(2)使用随機組合方式,代碼如下:
private string CreateRandomCode(int codeCount)
{
string allChar = "0,1,2,3,4,5,6,7,8,9";
string[] allCharArray = allChar.Split(\',\');
string randomCode = "";
int temp = -1;
Random rand = new Random();
for (int i = 0; i < codeCount; i++)
{
if (temp != -1)
{
rand = new Random(i * temp * ((int)DateTime.Now.Ticks));
}
int t = rand.Next(9);
if (temp == t)
{
return CreateRandomCode(codeCount);
}
temp = t;
randomCode += allCharArray[t];
}
return randomCode;
}
2、數字+字母驗證碼的實作,代碼如下:
private string CreateRandomCode(int codeCount)
{
string allChar = "0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,W,X,Y,Z,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z";
string[] allCharArray = allChar.Split(\',\');
string randomCode = "";
int temp = -1;
Random rand = new Random();
for (int i = 0; i < codeCount; i++)
{
if (temp != -1)
{
rand = new Random(i * temp * ((int)DateTime.Now.Ticks));
}
int t = rand.Next(61);
if (temp == t)
{
return CreateRandomCode(codeCount);
}
temp = t;
randomCode += allCharArray[t];
}
return randomCode;
}
3、漢字驗證碼的實作,代碼如下:
/**/
/*
此函數在漢字編碼範圍内随機建立含兩個元素的十六進制位元組數組,每個位元組數組代表一個漢字,并将
四個位元組數組存儲在object數組中。
參數:strlength,代表需要産生的漢字個數
*/
public static object[] CreateRegionCode(int strlength)
{
//定義一個字元串數組儲存漢字編碼的組成元素
string[] rBase = new String[16] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
Random rnd = new Random();
//定義一個object數組用來
object[] bytes = new object[strlength];
/**/
/*每循環一次産生一個含兩個元素的十六進制位元組數組,并将其放入bject數組中
每個漢字有四個區位碼組成
區位碼第1位和區位碼第2位作為位元組數組第一個元素
區位碼第3位和區位碼第4位作為位元組數組第二個元素
*/
for (int i = 0; i < strlength; i++)
{
//區位碼第1位
int r1 = rnd.Next(11, 14);
string str_r1 = rBase[r1].Trim();
//區位碼第2位
rnd = new Random(r1 * unchecked((int)DateTime.Now.Ticks) + i);//更換随機數發生器的種子避免産生重複值
int r2;
if (r1 == 13)
{
r2 = rnd.Next(0, 7);
}
else
{
r2 = rnd.Next(0, 16);
}
string str_r2 = rBase[r2].Trim();
//區位碼第3位
rnd = new Random(r2 * unchecked((int)DateTime.Now.Ticks) + i);
int r3 = rnd.Next(10, 16);
string str_r3 = rBase[r3].Trim();
//區位碼第4位
rnd = new Random(r3 * unchecked((int)DateTime.Now.Ticks) + i);
int r4;
if (r3 == 10)
{
r4 = rnd.Next(1, 16);
}
else if (r3 == 15)
{
r4 = rnd.Next(0, 15);
}
else
{
r4 = rnd.Next(0, 16);
}
string str_r4 = rBase[r4].Trim();
//定義兩個位元組變量存儲産生的随機漢字區位碼
byte byte1 = Convert.ToByte(str_r1 + str_r2, 16);
byte byte2 = Convert.ToByte(str_r3 + str_r4, 16);
//将兩個位元組變量存儲在位元組數組中
byte[] str_r = new byte[] { byte1, byte2 };
//将産生的一個漢字的位元組數組放入object數組中
bytes.SetValue(str_r, i);
}
return bytes;
}
三、具體執行個體
(執行個體1)
前台代碼display.aspx
<body>
<form id="form1" runat="server">
<div>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:Image ID="Image1" runat="server" ImageUrl="png.aspx" /><br />
<br />
<asp:Button ID="Button2" runat="server" OnClick="Button2_Click" Text="Button" />
<asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="True" OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged">
<asp:ListItem Value="3">預設</asp:ListItem>
<asp:ListItem Value="1">文字</asp:ListItem>
<asp:ListItem Value="2">數字</asp:ListItem>
<asp:ListItem Value="3">混合</asp:ListItem>
</asp:DropDownList></div>
</form>
</body>
背景代碼display.cs
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
switch (DropDownList1.SelectedValue)
{
case "1":
Image1.ImageUrl = "png.aspx?aa=1";
break;
case "2":
Image1.ImageUrl = "png.aspx?aa=2";
break;
case "3":
Image1.ImageUrl = "png.aspx?aa=3";
break;
}
}
protected void Button2_Click(object sender, EventArgs e)
{
if (TextBox1.Text == Session["gif"].ToString())
Response.Write("OK,正确");
else
Response.Write("驗證碼不符合");
}
背景代碼png.cs
public partial class png : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
switch (Request.QueryString["aa"])
{
case "1":
gif = stxt(10);
Session["gif"] = stxt(10);
break;
case "2":
gif = GetRandomint(4);
Session["gif"] = GetRandomint(4);
break;
case "3":
gif = CreateRandomCode(4);
Session["gif"] = CreateRandomCode(4);
break;
default:
gif = CreateRandomCode(4);
Session["gif"] = CreateRandomCode(4);
break;
}
CreateImage(Session["gif"].ToString());
}
private String GetRandomint(int codeCount)
{
Random random = new Random();
string min = "";
string max = "";
for (int i = 0; i < codeCount; i++)
{
min +="1";
max+="9";
}
return (random.Next(Convert.ToInt32(min),Convert.ToInt32(max)).ToString());
}
/**/
/*
此函數在漢字編碼範圍内随機建立含兩個元素的十六進制位元組數組,每個位元組數組代表一個漢字,并将
四個位元組數組存儲在object數組中。
參數:strlength,代表需要産生的漢字個數
*/
public static object[] CreateRegionCode(int strlength)
{
//定義一個字元串數組儲存漢字編碼的組成元素
string[] rBase = new String[16] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
Random rnd = new Random();
//定義一個object數組用來
object[] bytes = new object[strlength];
/**/
/*每循環一次産生一個含兩個元素的十六進制位元組數組,并将其放入bject數組中
每個漢字有四個區位碼組成
區位碼第1位和區位碼第2位作為位元組數組第一個元素
區位碼第3位和區位碼第4位作為位元組數組第二個元素
*/
for (int i = 0; i < strlength; i++)
{
//區位碼第1位
int r1 = rnd.Next(11, 14);
string str_r1 = rBase[r1].Trim();
//區位碼第2位
rnd = new Random(r1 * unchecked((int)DateTime.Now.Ticks) + i);//更換随機數發生器的種子避免産生重複值
int r2;
if (r1 == 13)
{
r2 = rnd.Next(0, 7);
}
else
{
r2 = rnd.Next(0, 16);
}
string str_r2 = rBase[r2].Trim();
//區位碼第3位
rnd = new Random(r2 * unchecked((int)DateTime.Now.Ticks) + i);
int r3 = rnd.Next(10, 16);
string str_r3 = rBase[r3].Trim();
//區位碼第4位
rnd = new Random(r3 * unchecked((int)DateTime.Now.Ticks) + i);
int r4;
if (r3 == 10)
{
r4 = rnd.Next(1, 16);
}
else if (r3 == 15)
{
r4 = rnd.Next(0, 15);
}
else
{
r4 = rnd.Next(0, 16);
}
string str_r4 = rBase[r4].Trim();
//定義兩個位元組變量存儲産生的随機漢字區位碼
byte byte1 = Convert.ToByte(str_r1 + str_r2, 16);
byte byte2 = Convert.ToByte(str_r3 + str_r4, 16);
//将兩個位元組變量存儲在位元組數組中
byte[] str_r = new byte[] { byte1, byte2 };
//将産生的一個漢字的位元組數組放入object數組中
bytes.SetValue(str_r, i);
}
return bytes;
}
private string stxt(int num)
{
Encoding gb = Encoding.GetEncoding("gb2312");
//調用函數産生10個随機中文漢字編碼
object[] bytes = CreateRegionCode(num);
string strtxt = "";
//根據漢字編碼的位元組數組解碼出中文漢字
for (int i = 0; i < num; i++)
{
strtxt += gb.GetString((byte[])Convert.ChangeType(bytes[i], typeof(byte[])));
}
return strtxt;
}
/// <summary>
/// 這個是使用字母,數字混合
/// </summary>
/// <param name="VcodeNum"></param>
/// <returns></returns>
private string CreateRandomCode(int codeCount)
{
string allChar = "0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,W,X,Y,Z,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z";
string[] allCharArray = allChar.Split(\',\');
string randomCode = "";
int temp = -1;
Random rand = new Random();
for (int i = 0; i < codeCount; i++)
{
if (temp != -1)
{
rand = new Random(i * temp * ((int)DateTime.Now.Ticks));
}
int t = rand.Next(61);
if (temp == t)
{
return CreateRandomCode(codeCount);
}
temp = t;
randomCode += allCharArray[t];
}
return randomCode;
}
private void CreateImage(string checkCode)
{
int iwidth = (int)(checkCode.Length * 20);
System.Drawing.Bitmap image = new System.Drawing.Bitmap(iwidth, 25);
Graphics g = Graphics.FromImage(image);
Font f = new System.Drawing.Font("Arial", 10, System.Drawing.FontStyle.Bold);
Brush b = new System.Drawing.SolidBrush(Color.White);
//g.FillRectangle(new System.Drawing.SolidBrush(Color.Blue),0,0,image.Width, image.Height);
g.Clear(Color.Black);
g.DrawString(checkCode, f, b, 3, 3);
Pen blackPen = new Pen(Color.Black, 0);
Random rand = new Random();
//for (int i=0;i<5;i++)
//{
// int y = rand.Next(image.Height);
// g.DrawLine(blackPen,0,y,image.W
idth,y);
//}
System.IO.MemoryStream ms = new System.IO.MemoryStream();
image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
Response.ClearContent();
Response.ContentType = "image/Jpeg";
Response.BinaryWrite(ms.ToArray());
g.Dispose();
image.Dispose();
}
}
(執行個體2):20101018續加
調用頁面前台代碼
<script language="Javascript">
function Regist()
{
var url = "";
url = "/GZPI/Service/Registry/ViewProtocol.aspx";
window.open(url);
return false;
}
function LoginClick()
{
if(document.Login.UserName.value == "")
{
alert("使用者名不能為空!");
return false;
}
document.Login.submit();
document.Login.Password.value = "";
return false;
}
function f_refreshtype()
{
var Image1 = document.getElementById("IMGCheckCode");
if (Image1 != null)
{
Image1.src = Image1.src + "?";
}
}
</script>
<TABLE cellSpacing="0" cellPadding="5" width="100%" border="0">
<TR>
<TD class="fontblack" align="right" width="30%">用 戶 名:</TD>
<TD vAlign="bottom" align="left" width="62%"><input id="Text1" style="BORDER-RIGHT: #43a7e2 1px solid; BORDER-TOP: #43a7e2 1px solid; BACKGROUND: #fcfcfc; BORDER-LEFT: #43a7e2 1px solid; BORDER-BOTTOM: #43a7e2 1px solid"
size="13" name="UserName" width="100px">
</TD>
</TR>
<TR>
<TD class="fontblack" align="right" height="23">密 碼:</TD>
<TD vAlign="bottom" align="left" height="23"><input id="Password1" style="BORDER-RIGHT: #43a7e2 1px solid; BORDER-TOP: #43a7e2 1px solid; BACKGROUND: #fcfcfc; BORDER-LEFT: #43a7e2 1px solid; BORDER-BOTTOM: #43a7e2 1px solid"
type="password" size="13" name="Password" width="100px">
</TD>
</TR>
<TR>
<TD class="fontblack" align="right" height="23">校 驗 碼:</TD>
<TD valign="top" align="left" height="23"><FONT face="宋體"><INPUT id="CheckCode" style="BORDER-RIGHT: #43a7e2 1px solid; BORDER-TOP: #43a7e2 1px solid; BACKGROUND: #fcfcfc; BORDER-LEFT: #43a7e2 1px solid; BORDER-BOTTOM: #43a7e2 1px solid"
width="100px" size="13" name="CheckCode"> </FONT><a style="CURSOR: hand" onclick="f_refreshtype()" title="看不清楚?點選擷取新的校驗碼!" border="0"><IMG id="IMGCheckCode" src="../GenerateCheckCode.aspx"></a>
</TD>
</TR>
<TR vAlign="bottom" align="center">
<TD class="dlbuttom" colSpan="2" height="23"><input id="Image1" style="CURSOR: hand" onclick="return LoginClick();" tabIndex="3" type="image"
height="17" width="55" src="images/login.gif" border="0" name="OkButton">
<input type="image" onClick="return Regist();" border=\'0\' src=\'images/zuce.gif\' width=\'55\'
height=\'17\' ID="Image2" NAME="Image2">
</TD>
</TR>
</TABLE>
調用頁面背景代碼
private void OK_Click(object sender, System.EventArgs e)
{
if (!CheckCodeSame(CheckCode.Text.Trim()))
{
System.Web.HttpContext.Current.Response.Write("<Script Language=\'JavaScript\'>window.alert(\'校驗碼錯誤!請重新輸入!\');window.close();</script>");
return;
}
int userType = 1;
try
{
userType = int.Parse(UserType.Text);
}
catch
{
}
GatewayManager gateway = new GatewayManager(corpCode.Text,collegeCode.Text,chargeCode.Text,userName.Text,password.Text,userType);
gateway.Login(this);
}
/// <summary>
/// 判斷輸入的校驗碼是否正确
/// </summary>
/// <param name="checkCode"></param>
/// <returns></returns>
public static bool CheckCodeSame(string checkCode)
{
bool bSame = false; ;
if (HttpContext.Current.Session["CheckCode"] != null)
{
if (checkCode.ToUpper() == HttpContext.Current.Session["CheckCode"].ToString().ToUpper())
{
bSame = true;
}
}
return bSame;
}
生成驗證碼前台檔案
<HTML>
<HEAD>
<title>GenerateCheckCode</title>
<meta name="GENERATOR" Content="Microsoft Visual Studio .NET 7.1">
<meta name="CODE_LANGUAGE" Content="C#">
<meta name="vs_defaultClientScript" content="JavaScript">
<meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">
</HEAD>
<body>
<form id="form1" runat="server">
<div><FONT face="宋體"></FONT>
</div>
</form>
</body>
</HTML>
生成驗證碼背景檔案
using System;
using System.Collections;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace GZPI.Gateway
{
/// <summary>
/// GenerateCheckCode 的摘要說明。
/// </summary>
public class GenerateCheckCode : System.Web.UI.Page
{
private void Page_Load(object sender, System.EventArgs e)
{
// 在此處放置使用者代碼以初始化頁面
this.CreateCheckCodeImage(GenerateCheckCodes(4));
}
#region Web 窗體設計器生成的代碼
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: 該調用是 ASP.NET Web 窗體設計器所必需的。
//
InitializeComponent();
base.OnInit(e);
}
/// <summary>
/// 設計器支援所需的方法 - 不要使用代碼編輯器修改
/// 此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.Load += new System.EventHandler(this.Page_Load);
}
#endregion
private string GenerateCheckCodes(int iCount)
{
int number;
string checkCode = String.Empty;
int iSeed = DateTime.Now.Millisecond;
System.Random random = new Random(iSeed);
for (int i = 0; i < iCount; i++)
{
number = random.Next(10);
checkCode += number.ToString();
}
Session["CheckCode"] = checkCode;
return checkCode;
}
private void CreateCheckCodeImage(string checkCode)
{
if (checkCode == null || checkCode.Trim() == String.Empty)
return;
int iWordWidth = 15;
int iImageWidth = checkCode.Length * iWordWidth;
Bitmap image = new Bitmap(iImageWidth, 20);
Graphics g = Graphics.FromImage(image);
try
{
//生成随機生成器
Random random = new Random();
//清空圖檔背景色
g.Clear(Color.White);
//畫圖檔的背景噪音點
for (int i = 0; i < 20; i++)
{
int x1 = random.Next(image.Width);
int x2 = random.Next(image.Width);
int y1 = random.Next(image.Height);
int y2 = random.Next(image.Height);
g.DrawLine(new Pen(Color.Silver), x1, y1, x2, y2);
}
//畫圖檔的背景噪音線
for (int i = 0; i < 2; i++)
{
int x1 = 0;
int x2 = image.Width;
int y1 = random.Next(image.Height);
int y2 = random.Next(image.Height);
if (i == 0)
{
g.DrawLine(new Pen(Color.Gray, 2), x1, y1, x2, y2);
}
}
for (int i = 0; i < checkCode.Length; i++)
{
string Code = checkCode[i].ToString();
int xLeft = iWordWidth * (i);
random = new Random(xLeft);
int iSeed = DateTime.Now.Millisecond;
int iValue = random.Next(iSeed) % 4;
if (iValue == 0)
{
Font font = new Font("Arial", 13, (FontStyle.Bold | System.Drawing.FontStyle.Italic));
Rectangle rc = new Rectangle(xLeft, 0, iWordWidth, image.Height);
LinearGradientBrush brush = new LinearGradientBrush(rc, Color.Blue, Color.Red, 1.5f, true);
g.DrawString(Code, font, brush, xLeft, 2);
}
else if (iValue == 1)
{
Font font = new System.Drawing.Font("楷體", 13, (FontStyle.Bold));
Rectangle rc = new Rectangle(xLeft, 0, iWordWidth, image.Height);
LinearGradientBrush brush = new LinearGradientBrush(rc, Color.Blue, Color.DarkRed, 1.3f, true);
g.DrawString(Code, font, brush, xLeft, 2);
}
else if (iValue == 2)
{
Font font = new System.Drawing.Font("宋體", 13, (System.Drawing.FontStyle.Bold));
Rectangle rc = new Rectangle(xLeft, 0, iWordWidth, image.Height);
LinearGradientBrush brush = new LinearGradientBrush(rc, Color.Green, Color.Blue, 1.2f, true);
g.DrawString(Code, font, brush, xLeft, 2);
}
else if (iValue == 3)
{
Font font = new System.Drawing.Font("黑體", 13, (System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Bold));
Rectangle rc = new Rectangle(xLeft, 0, iWordWidth, image.Height);
LinearGradientBrush brush = new LinearGradientBrush(rc, Color.Blue, Color.Green, 1.8f, true);
g.DrawString(Code, font, brush, xLeft, 2);
}
}
//////畫圖檔的前景噪音點
//for (int i = 0; i < 8; i++)
//{
// int x = random.Next(image.Width);
// int y = random.Next(image.Height);
// image.SetPixel(x, y, Color.FromArgb(random.Next()));
//}
//畫圖檔的邊框線
g.DrawRectangle(new Pen(Color.Silver), 0, 0, image.Width - 1, image.Height - 1);
System.IO.MemoryStream ms = new System.IO.MemoryStream();
image.Save(ms, System.Drawing.Imaging.ImageFormat.Gif);
Response.ClearContent();
Response.BinaryWrite(ms.ToArray());
}
finally
{
g.Dispose();
image.Dispose();
}
}
}
}
四、效果圖展示
驗證碼數字

驗證碼數字+字母
驗證碼漢字