随机校验码的生成和使用
在一些网页以及窗口应用程序中,经常会碰到一些随机校验码的使用问题。其作用是可以增强系统的安全性,防止恶意注册,恶意使用等。校验码大致会有以下几种形式:全部是英文字符,如数字,大小写字符混合,汉字,随机的一些简单数学试题等。
其图案显示的内容可以随机更改,现对其实现原理做一点简单说明,以供大家交流学习。
具体代码可以在http://download.csdn.net/source/2862637下载
第一步,是随机图片的生成。
需要在窗口上添加一个PictureBox的控件,用来显示将来生成的随机图片。然后就在后台代码中自定义一个Image,然后定义一个画笔,在刚刚生成的图片上进行绘制图形,如增加一些噪声点,干扰线等。当然,还需要将我们随机生成的一些字符信息写到图片上,以便能够显示。
具体的代码如下:
private void CreateCheckCodeImage(string checkCode)
{
if (checkCode == null || checkCode.Trim() == String.Empty)
return;
Bitmap image = new Bitmap((int)Math.Ceiling((checkCode.Length * 20.5)), 22);
Graphics g = Graphics.FromImage(image);
try
{
Random random = new Random();
g.FillRectangle(Brushes.White, 0, 0, image.Width, image.Height);
for (int i = 0; i < 2; 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.Black), x1, y1, x2, y2);
}
Font font = new System.Drawing.Font("微软雅黑", 12, (System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Italic));
//使用系统画刷,在一个新矩形里画图
System.Drawing.Drawing2D.LinearGradientBrush brush = new LinearGradientBrush(
new Rectangle(0, 0, image.Width, image.Height), Color.Blue, Color.DarkRed,
0, true);
g.DrawString(checkCode, font, brush , 2, 2);
for (int i = 0; i < 100; i++)
{
int x = random.Next(image.Width);
int y = random.Next(image.Height);
//生成随机的图形噪音点
image.SetPixel(x, y, Color.FromArgb(random.Next()));
}
//将生成的图片绑定到窗口的PictureBox控件上,进行显示
this.picCheck.Width = image.Width;
this.picCheck.Height = image.Height;
this.picCheck.BackgroundImage = image;
}
finally
{
g.Dispose();
}
}
以上代码是生成图片,显示的是得到的随机内容,这里的图片设置较为简单,如果愿意,可以加上其他的效果,如扭曲变化,翻转,倒影等,在此不做具体阐述。
第二步是,如何得到随机的文字内容?
我们会使用getCheckCode()函数来生成随机内容,在这个函数里,调用了三个不同的函数,以便分别能够生成字符,汉字,以及随机数学试题。具体代码如下:
private string getCheckCode()
{
Random random = new Random();
//根据随机生成的caseNum,来确定所使用的图案内容
int caseNum = random.Next() % 3;
checkCode = string.Empty;
switch (caseNum)
{
case 0:
//普通校验码
getEnglishCode();
break;
case 1:
//汉字校验码
getChineseCode();
break;
case 2:
//随机测试题校验码
getNumCode();
break;
}
return checkCode;
}
首先通过一个随机数,来确定使用哪种校验码。
下面是三种不同校验码的生成。
①普通校验码
private string getEnglishCode()
{
Random random = new Random();
int number;
char code;
for (int i = 0; i < 4; i++)
{
number = random.Next();
//如果是偶数,生成一个随机数字
if (number % 2 == 0)
code = (char)('0' + (char)(number % 10));
else//如果为奇数,生成一个随机字符
code = (char)('A' + (char)(number % 26));
//将该字符存储到验证码中
checkCode += code.ToString();
}
return checkCode;
}
②,汉字校验码
private string getChineseCode()
{
Random random = new Random();
int strlength = 4;
//定义一个字符串数组储存汉字编码的组成元素
string[] r = new String[16] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
//定义一个object数组用来
object[] bytes = new object[strlength];
/**/
/*每循环一次产生一个含两个元素的十六进制字节数组,并将其放入bject数组中
每个汉字有四个区位码组成
区位码第1位和区位码第2位作为字节数组第一个元素
区位码第3位和区位码第4位作为字节数组第二个元素
*/
for (int i = 0; i < strlength; i++)
{
//区位码第1位
int r1 = random.Next(11, 14);
string str_r1 = r[r1].Trim();
//区位码第2位
random = new Random(r1 * unchecked((int)DateTime.Now.Ticks) + i);
//更换随机数发生器的种子避免产生重复值
int r2;
if (r1 == 13)
r2 = random.Next(0, 7);
else
r2 = random.Next(0, 16);
string str_r2 = r[r2].Trim();
//区位码第3位
random = new Random(r2 * unchecked((int)DateTime.Now.Ticks) + i);
int r3 = random.Next(10, 16);
string str_r3 = r[r3].Trim();
//区位码第4位
random = new Random(r3 * unchecked((int)DateTime.Now.Ticks) + i);
int r4;
if (r3 == 10)
{
r4 = random.Next(1, 16);
}
else if (r3 == 15)
{
r4 = random.Next(0, 15);
}
else
{
r4 = random.Next(0, 16);
}
string str_r4 = r[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);
}
Encoding gb = Encoding.GetEncoding("gb2312");
//根据汉字编码的字节数组解码出中文汉字
for (int m = 0; m < strlength; m++)
checkCode += gb.GetString((byte[])Convert.ChangeType(bytes[m], typeof(byte[])));
return checkCode;
}
③,随机数学试题生成
private string getNumCode()
{
flag = true;
result = 0;
Random rand = new Random();
int op = rand.Next() % 4;
int a = rand.Next() % 10;
int b = rand.Next() % 10;
switch (op)
{
case 0:
{
result = a + b;
checkCode = a + "+" + b + " =";
}
break;
case 1:
{
result = a - b;
checkCode = a + "-" + b + " =";
}
break;
case 2:
{
result = a * b;
checkCode = a + "*" + b + " =";
}
break;
}
return checkCode;
}
第三步,是如何将用户输入的校验信息与图片显示的信息进行比较匹配。
当点击Logon按钮的时候,会发生如下的事件:
private void btnLogin_Click(object sender, EventArgs e)
{
if(flag)
checkCode = result.ToString();
if (txtUserName.Text == "Admin" && txtPwd.Text == "admin" && txtCheck.Text == checkCode)
{
MessageBox.Show("Welcome " + txtUserName.Text + " and your password is " + txtPwd.Text + " and you checkCode is " + checkCode,
"登陆成功",MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
MessageBox.Show("你的用户名或者密码,或者验证码错误","温馨提示",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
在程序中,使用了一个全局变量checkCode,用来接收随机生成的校验信息,然后与用户输入的验证码进行比较,据此来判断是否正确输入。
如果是随机的数学试题,(flag = true),则将试题的结果传递给checkCode,用来跟用户输入的计算结果进行比较判断。
其他的比如刷新,重新获取操作较为简单,在此不做阐述,具体可以参考代码。
以上就是一个利于随机校验图片的实现,当然,我们可以将其编译成为一个dll控件,这样在其他的程序中都可以直接调用,使用起来也较为方便。
以上就是对随机校验码实现的一点简单说明,不免显得有些啰嗦,但第一次写技术性的文字,不知该如何下手,希望大家多多交流,共同进步。