1、为什么要加验证码?
因为加了验证码可以防御别人攻击你的网站,举个例子:别人可以用webbrowser控件做一个模拟浏览器,并且模拟提交表单(模拟填写表单资料和点击提交按钮),那么你的服务器必须接收这些表单传过来的值,并且做判断,是否正确。这样一来,别人可以无限占用你的服务器资源,而且账号密码都不安全,万一被别人搞个循环1个1个账号轮询的话,很有可能让别人破解了你的资料信息,所以安全性稍微高点的网站登录都有彩色图片验证码。
2、为什么彩色验证码图片可以防御别人的攻击?
因为当别人用轮询技术模拟登录的时候,他并不知道你的验证码是什么,也获取不到,因为这是一张图片,电脑并不能识别里面的数字是什么(除非破解验证码里面的干扰,再利用相关的图片识别技术有可能读出验证码,这里先不扯这个)。读不出验证码就没有机会轮询访问了,当然我们后台判断的时候一定要先判断验证码是否正确,以防止占用服务器资源。
3、随机数 Code
①数字随机数
1
///
<summary>
2
///
数字随机数
3
///
</summary>
4
///
<returns></returns>
5
private
string
GetRndNum()
6
{
7
string
code
=
string
.Empty;
8
Random random
=
new
Random();
9
for
(
int
i
=
0
; i
<
4
; i
++
)
10
{
11
code
=
code
+
random.Next(
9
).ToString();
12
}
13
return
code;
14
}
②字符串随机数
1
///
<summary>
2
///
字符串验证码
3
///
</summary>
4
///
<returns></returns>
5
private
string
GetRndStr()
6
{
7
string
Vchar
=
"
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
"
;
8
string
[] VcArray
=
Vchar.Split(
'
,
'
);
9
string
checkCode
=
string
.Empty;
10
Random rand
=
new
Random();
11
for
(
int
i
=
0
; i
<
4
; i
++
)
12
{
13
rand
=
new
Random(
unchecked
((
int
)DateTime.Now.Ticks));
//
为了得到不同的随机序列
14
int
t
=
rand.Next(VcArray.Length);
//
The exclusive upper bound of the random number to be generated. maxValue must be greater than or equal to zero,下标从0开始
15
checkCode
+=
VcArray[t];
16
}
17
return
checkCode;
18
}
③中文随机数
1
///
<summary>
2
///
随机中文码
3
///
</summary>
4
///
<returns></returns>
5
private
string
GetRndCh()
6
{
7
System.Text.Encoding gb
=
System.Text.Encoding.Default;
//
获取GB2312编码页(表)
8
object
[] bytes
=
CreateRegionCode(
4
);
//
调用函数产生4个随机中文汉字编码
9
string
[] str
=
new
string
[
4
];
10
System.Text.StringBuilder sb
=
new
System.Text.StringBuilder();
11
for
(
int
i
=
0
; i
<
4
; i
++
)
12
{
13
//
根据汉字编码的字节数组解码出中文汉字
14
str[i]
=
gb.GetString((
byte
[])Convert.ChangeType(bytes[i],
typeof
(
byte
[])));
15
sb.Append( str[i].ToString());
16
}
17
return
sb.ToString ();
18
}
19
20
21
///
<summary>
22
///
产生随机中文汉字编码
23
///
</summary>
24
///
<param name="strlength"></param>
25
///
<returns></returns>
26
private
static
object
[] CreateRegionCode(
int
strlength)
27
{
28
//
定义一个字符串数组储存汉字编码的组成元素
29
string
[] rBase
=
new
String[
16
] {
"
0
"
,
"
1
"
,
"
2
"
,
"
3
"
,
"
4
"
,
"
5
"
,
"
6
"
,
"
7
"
,
"
8
"
,
"
9
"
,
"
a
"
,
"
b
"
,
"
c
"
,
"
d
"
,
"
e
"
,
"
f
"
};
30
Random rnd
=
new
Random();
31
object
[] bytes
=
new
object
[strlength];
32
33
for
(
int
i
=
0
; i
<
strlength; i
++
)
34
{
35
//
区位码第1位
36
int
r1
=
rnd.Next(
11
,
14
);
37
string
str_r1
=
rBase[r1].Trim();
38
39
//
区位码第2位
40
rnd
=
new
Random(r1
*
unchecked
((
int
)DateTime.Now.Ticks)
+
i);
41
int
r2;
42
if
(r1
==
13
)
43
{
44
r2
=
rnd.Next(
0
,
7
);
45
}
46
else
47
{
48
r2
=
rnd.Next(
0
,
16
);
49
}
50
string
str_r2
=
rBase[r2].Trim();
51
52
//
区位码第3位
53
rnd
=
new
Random(r2
*
unchecked
((
int
)DateTime.Now.Ticks)
+
i);
//
更换随机种子
54
int
r3
=
rnd.Next(
10
,
16
);
55
string
str_r3
=
rBase[r3].Trim();
56
57
//
区位码第4位
58
rnd
=
new
Random(r3
*
unchecked
((
int
)DateTime.Now.Ticks)
+
i);
59
int
r4;
60
if
(r3
==
10
)
61
{
62
r4
=
rnd.Next(
1
,
16
);
63
}
64
else
if
(r3
==
15
)
65
{
66
r4
=
rnd.Next(
0
,
15
);
67
}
68
else
69
{
70
r4
=
rnd.Next(
0
,
16
);
71
}
72
string
str_r4
=
rBase[r4].Trim();
73
74
//
定义两个字节变量存储产生的随机汉字区位码
75
byte
byte1
=
Convert.ToByte(str_r1
+
str_r2,
16
);
76
byte
byte2
=
Convert.ToByte(str_r3
+
str_r4,
16
);
77
78
//
将两个字节变量存储在字节数组中
79
byte
[] str_r
=
new
byte
[] { byte1, byte2 };
80
81
//
将产生的一个汉字的字节数组放入object数组中
82
bytes.SetValue(str_r, i);
83
}
84
return
bytes;
85
}
4、现在有了素材(随机数),那么再加上图片和困扰就完成了彩色图片验证码--困扰背景+图片Code
1
///
<summary>
2
///
画图片的背景图,干扰
3
///
</summary>
4
///
<param name="checkCode"></param>
5
///
<returns></returns>
6
private
Bitmap CreateImages(
string
checkCode,
string
type)
7
{
8
int
step
=
0
;
9
if
(type
==
"
ch
"
)
10
{
11
step
=
5
;
//
中文字符比较大,所以字距要比较大
12
}
13
int
iwidth
=
(
int
)(checkCode.Length
*
(
13
+
step));
14
System.Drawing.Bitmap image
=
new
System.Drawing.Bitmap(iwidth,
22
);
15
Graphics g
=
Graphics.FromImage(image);
16
17
g.Clear(Color.White);
//
清除背景色
18
19
Color[] c
=
{ Color.Black, Color.Red, Color.DarkBlue, Color.Green, Color.Orange, Color.Brown, Color.DarkCyan, Color.Purple };
//
定义随机颜色
20
21
string
[] font
=
{
"
Verdana
"
,
"
Microsoft Sans Serif
"
,
"
Comic Sans MS
"
,
"
Arial
"
,
"
宋体
"
};
22
Random rand
=
new
Random();
23
24
for
(
int
i
=
0
; i
<
50
; i
++
)
25
{
26
int
x1
=
rand.Next(image.Width);
27
int
x2
=
rand.Next(image.Width);
28
int
y1
=
rand.Next(image.Height);
29
int
y2
=
rand.Next(image.Height);
30
g.DrawLine(
new
Pen(Color.LightGray,
1
), x1,y1,x2,y2);
//
根据坐标画线
31
}
32
33
for
(
int
i
=
0
; i
<
checkCode.Length; i
++
)
34
{
35
int
cindex
=
rand.Next(
7
);
36
int
findex
=
rand.Next(
5
);
37
38
Font f
=
new
System.Drawing.Font(font[findex],
10
, System.Drawing.FontStyle.Bold);
39
Brush b
=
new
System.Drawing.SolidBrush(c[cindex]);
40
int
ii
=
4
;
41
if
((i
+
1
)
%
2
==
0
)
42
{
43
ii
=
2
;
44
}
45
g.DrawString(checkCode.Substring(i,
1
), f, b,
3
+
(i
*
(
12
+
stepw)), ii);
46
}
47
48
g.DrawRectangle(
new
Pen(Color.Black,
0
),
0
,
0
, image.Width
-
1
, image.Height
-
1
);
49
50
System.IO.MemoryStream ms
=
new
System.IO.MemoryStream();
51
return
image;
52
}
5、总结
根据你要的随机数和背景就可以返回BitMap数组,然后把BitMap数组以图片形式存到内存流,就可以返回了。在这里只提供思路与制作方法并没有提供全部代码与封装过程,若对代码有疑问或者需要实例可以加QQ群128584255,大家讨论学习一下。