服务器之家

服务器之家 > 正文

12306奇葩验证码引发思考之C#实现验证码程序

时间:2021-11-05 10:57     来源/作者:C#教程网

近日铁路订票网“12306”又出现多道另类考题,竟要订票者在8个图案中“点击图中所有美男子”、“请点击下图中所有的非智能眼镜”、“请点击下图中所有的博斯普鲁斯海峡”,网友吐槽:比高考题还难,到底是什么样子的,先跟大家分享一下几个例子:

12306奇葩验证码引发思考之C#实现验证码程序

哈哈,是有点奇葩的验证码,怪不得有人会说“妈妈我已经找不到回家”,这让分秒必争的春运网上抢票者瞬间傻眼,九成网友已经被打败……

正巧小编最近也在研究验证码,参考了许多网上案例,整理了一篇文章特分享给大家。

验证码的一般编写思路为:
       1.定义验证码字符长度;
       2.根据长度随机生成验证码字符串;
       3.将验证码字符串转换成图片形式,并在图片中生成随机噪声点和声线(对验证码进行模糊识别处理);
       4.显示结果。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
///
 /// 生成随机验证码
 ///
 /// 验证码长度
 ///
 public string CreateIdentifyingCode(int CodeLen)
 {
 if (CodeLen < 1)
  return String.Empty;
 int num;
 string checkcode = String.Empty;
 Random random = new Random();
 for (int index = 0; index < CodeLen; index++)
 {
  num = random.Next();
  if (num % 2 == 0)
  checkcode += (char)('0' + (char)(num % 10));
  else
  checkcode += (char)('A' + (char)(num % 26));
 }
 return checkcode;
 }
-------------------------------------------------------------------------------------------------
 ///
 /// 生成验证码图片
 ///
 ///
 ///
 private void CreateCheckCodeImage(string checkcode)
 {
  if (checkcode == null || checkcode.Trim() == String.Empty)
  return;
  //创建图片大小
  System.Drawing.Bitmap image = new  System.Drawing.Bitmap((int)Math.Ceiling(checkcode.Length*12.5),22);
  //创建画板
  Graphics graphic = Graphics.FromImage(image);
 
  try
  {
  Random random = new Random();
  graphic.Clear(Color.White);
  int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
  //画图片背景噪声线
  for (int index = 0; index < 25; index++)
  {
   x1 = random.Next(image.Width);
   y1 = random.Next(image.Height);
   x2 = random.Next(image.Width);
   y2 = random.Next(image.Height);
   graphic.DrawLine(new Pen(Color.Silver),x1,y1,x2,y2);
  }
  Font font = new System.Drawing.Font("Helvetica", 12, (FontStyle.Bold |FontStyle.Italic));
  LinearGradientBrush brush = new LinearGradientBrush(new Rectangle(0, 0, image.Width, image.Height),Color.Blue,Color.DarkBlue,1.2f,true);
  graphic.DrawString(checkcode,font,brush,2,2);
 
  int x = 0;
  int y = 0;
  // 画图片的前景噪声点
  for (int index = 0; index < 100; index++)
  {
   x = random.Next(image.Width);
   y = random.Next(image.Height);
   image.SetPixel(x,y,Color.FromArgb(random.Next()));
  }
  //画图片的边框线
  graphic.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.ContentType = "image/Gif";
  Response.BinaryWrite(ms.ToArray());
  }
  finally
  {
  graphic.Dispose();
  image.Dispose();
  }
 }

以上所生成的为简单的验证码。接下来我从其他的博客中学习了其他形式的效果。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 图片画线特殊效果:贝塞尔曲线 */
  Graphics graph = Graphics.FromImage(image);
  graph.Clear(Color.WhiteSmoke);
  Point[] myArray ={
     new Point(random.Next(150),random.Next(50)),
     new Point(random.Next(150),random.Next(50)),
     new Point(random.Next(150),random.Next(50)),
     new Point(random.Next(150),random.Next(50)),
     new Point(random.Next(150),random.Next(50)),
     new Point(random.Next(150),random.Next(50)),
     new Point(random.Next(150),random.Next(50)),
     new Point(random.Next(150),random.Next(50)),
     new Point(random.Next(150),random.Next(50)),
     new Point(random.Next(150),random.Next(50))
    };
  Pen myPen = new Pen(Color.Blue, 1);
  GraphicsPath myPath = new GraphicsPath();
  myPath.AddBeziers(myArray);
  graph.DrawPath(myPen, myPath);

验证码字符颜色变换效果:实现该效果,我们首先来定义一个颜色集合,然后通过for循环使其随机改变字体颜色则可。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#region 定义颜色数组
Color[] colors = { Color.Blue, Color.Green, Color.Red, Color.Gold, Color.Black, Color.Chocolate, Color.Orange, Color.Purple };
public Color[] Colors
{
 get { return colors; }
 set { colors = value; }
}
#endregion
Brush brush;
int colornum;
for(int i=0; i
{
 colornum = random.Next(Colors.Length - 1);
 brush = new System.Drawing.SolidBrush(Colors[cindex]);
 
 //利用DrawString函数进行颜色填充就可以了。
}

 同样的原理我们也可以定义一个字体的数组来进行验证码字体切换。代码和颜色的类似,这里就不加以累赘。
接下来看看如何使得验证码的字体进行扭曲。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
private const double PI = 3.1415926535897932384626433832795;
 private const double PI2 = 6.283185307179586476925286766559;
 ///
 /// 波形滤镜效果函数
 ///
 ///
 ///
 ///
 ///
 ///
 public System.Drawing.Bitmap TwistImage(Bitmap srcbmp, double dmultvalue, double dphase)
 {
  System.Drawing.Bitmap destbmp = new Bitmap(srcbmp.Width,srcbmp.Height);
  System.Drawing.Graphics graph = System.Drawing.Graphics.FromImage(destbmp);
  //填充背景图为白色
  graph.FillRectangle(new SolidBrush(System.Drawing.Color.White), 0, 0, destbmp.Width, destbmp.Height);
  graph.Dispose();
  double dbaselen = (double)destbmp.Width;
  for (int i = 0; i < destbmp.Width; i++)
  {
  for (int j = 0; j < destbmp.Height; j++)
  {
   double dx = 0;
   dx = (PI2 * (double)j) / dbaselen;
   dx += dphase;
 
   double dy = Math.Sin(dx);
 
   int noldx = 0, noldy = 0;
   noldx = i + (int)(dy * dmultvalue);
   noldy = j + (int)(dy * dmultvalue);
   System.Drawing.Color color = srcbmp.GetPixel(i, j);
   if (noldx >= 0 && noldx < destbmp.Width && noldy >= 0 && noldy < destbmp.Height)
   destbmp.SetPixel(noldx, noldy, color);
  }
  }
  return destbmp;
 }

上面代码是参考了这段代码进行的学习<C#.net 好用的验证码代码 汉字-变色-扭曲-波动 >,代码如下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Drawing;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
 
public partial class study_CheckCode2 : System.Web.UI.Page
{
 protected void Page_Load(object sender, EventArgs e)
 {
 string code = CreateVerifyCode();  //取随机码
 CreateImageOnPage(code, this.Context); // 输出图片
 Response.Cookies.Add(new HttpCookie("CheckCode", code.ToUpper()));// 使用Cookies取验证码的值
 }
 
 #region 验证码长度(默认4个验证码的长度)
 int length = 4;
 public int Length
 {
 get { return length; }
 set { length = value; }
 }
 #endregion
 
 #region 验证码字体大小(为了显示扭曲效果,默认40像素,可以自行修改)
 int fontSize = 40;
 public int FontSize
 {
 get { return fontSize; }
 set { fontSize = value; }
 }
 #endregion
 
 #region 边框补(默认1像素)
 int padding = 2;
 public int Padding
 {
 get { return padding; }
 set { padding = value; }
 }
 #endregion
 
 #region 是否输出燥点(默认不输出)
 bool chaos = true;
 public bool Chaos
 {
 get { return chaos; }
 set { chaos = value; }
 }
 #endregion
 
 #region 输出燥点的颜色(默认灰色)
 Color chaosColor = Color.LightGray;
 public Color ChaosColor
 {
 get { return chaosColor; }
 set { chaosColor = value; }
 }
 #endregion
 
 #region 自定义背景色(默认白色)
 Color backgroundColor = Color.White;
 public Color BackgroundColor
 {
 get { return backgroundColor; }
 set { backgroundColor = value; }
 }
 #endregion
 
 #region 自定义随机颜色数组
 Color[] colors = { Color.Black, Color.Red, Color.DarkBlue, Color.Green, Color.Orange, Color.Brown, Color.DarkCyan, Color.Purple };
 public Color[] Colors
 {
 get { return colors; }
 set { colors = value; }
 }
 #endregion
 
 #region 自定义字体数组
 string[] fonts = { "Arial", "Georgia" };
 public string[] Fonts
 {
 get { return fonts; }
 set { fonts = value; }
 }
 #endregion
 
 #region 自定义随机码字符串序列(使用逗号分隔)
 //string codeSerial = "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,v,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 codeSerial = "阿,保,持,的,法,规,和,东,三,省,问,我,惹,你,诶,没,改,变,揍,屁,股,吧";
 public string CodeSerial
 {
 get { return codeSerial; }
 set { codeSerial = value; }
 }
 #endregion
 
 #region 产生波形滤镜效果
 
 private const double PI = 3.1415926535897932384626433832795;
 private const double PI2 = 6.283185307179586476925286766559;
 
 /// <summary>
 /// 正弦曲线Wave扭曲图片(Edit By 51aspx.com)
 /// </summary>
 /// <param name="srcBmp">图片路径</param>
 /// <param name="bXDir">如果扭曲则选择为True</param>
 /// <param name="dMultValue">波形的幅度倍数,越大扭曲的程度越高,一般为3</param>
 /// <param name="dPhase">波形的起始相位,取值区间[0-2*PI)</param>
 /// <returns></returns>
 public System.Drawing.Bitmap TwistImage(Bitmap srcBmp, bool bXDir, double dMultValue, double dPhase)
 {
 System.Drawing.Bitmap destBmp = new Bitmap(srcBmp.Width, srcBmp.Height);
 
 // 将位图背景填充为白色
 System.Drawing.Graphics graph = System.Drawing.Graphics.FromImage(destBmp);
 graph.FillRectangle(new SolidBrush(System.Drawing.Color.White), 0, 0, destBmp.Width, destBmp.Height);
 graph.Dispose();
 
 double dBaseAxisLen = bXDir ? (double)destBmp.Height : (double)destBmp.Width;
 
 for (int i = 0; i < destBmp.Width; i++)
 {
  for (int j = 0; j < destBmp.Height; j++)
  {
  double dx = 0;
  dx = bXDir ? (PI2 * (double)j) / dBaseAxisLen : (PI2 * (double)i) / dBaseAxisLen;
  dx += dPhase;
  double dy = Math.Sin(dx);
 
  // 取得当前点的颜色
  int nOldX = 0, nOldY = 0;
  nOldX = bXDir ? i + (int)(dy * dMultValue) : i;
  nOldY = bXDir ? j : j + (int)(dy * dMultValue);
 
  System.Drawing.Color color = srcBmp.GetPixel(i, j);
  if (nOldX >= 0 && nOldX < destBmp.Width
   && nOldY >= 0 && nOldY < destBmp.Height)
  {
   destBmp.SetPixel(nOldX, nOldY, color);
  }
  }
 }
 return destBmp;
 }
 #endregion
 
 #region 生成校验码图片
 public Bitmap CreateImageCode(string code)
 {
 int fSize = FontSize;
 int fWidth = fSize + Padding;
 
 int imageWidth = (int)(code.Length * fWidth) + 30 + Padding * 2;
 int imageHeight = fSize * 2 + Padding;
 
 System.Drawing.Bitmap image = new System.Drawing.Bitmap(imageWidth, imageHeight);
 
 Graphics g = Graphics.FromImage(image);
 
 g.Clear(BackgroundColor);
 
 Random rand = new Random();
 
 //给背景添加随机生成的燥点
 if (this.Chaos)
 {
 
  Pen pen = new Pen(ChaosColor, 0);
  int c = Length * 10;
 
  for (int i = 0; i < c; i++)
  {
  int x = rand.Next(image.Width);
  int y = rand.Next(image.Height);
 
  g.DrawRectangle(pen, x, y, 1, 1);
  }
 }
 
 int left = 0, top = 0, top1 = 1, top2 = 1;
 
 int n1 = (imageHeight - FontSize - Padding * 2);
 int n2 = n1 / 4;
 top1 = n2;
 top2 = n2 * 2;
 
 Font f;
 Brush b;
 
 int cindex, findex;
 
 //随机字体和颜色的验证码字符
 for (int i = 0; i < code.Length; i++)
 {
  cindex = rand.Next(Colors.Length - 1);
  findex = rand.Next(Fonts.Length - 1);
 
  f = new System.Drawing.Font(Fonts[findex], fSize, System.Drawing.FontStyle.Bold);
  b = new System.Drawing.SolidBrush(Colors[cindex]);
 
  if (i % 2 == 1)
  {
  top = top2;
  }
  else
  {
  top = top1;
  }
 
  left = i * fWidth;
 
  g.DrawString(code.Substring(i, 1), f, b, left, top);
 }
 
 //画一个边框 边框颜色为Color.Gainsboro
 g.DrawRectangle(new Pen(Color.Gainsboro, 0), 0, 0, image.Width - 1, image.Height - 1);
 g.Dispose();
 
 //产生波形(Add By 51aspx.com)
 image = TwistImage(image, true, 8, 4);
 
 return image;
 }
 #endregion
 
 #region 将创建好的图片输出到页面
 public void CreateImageOnPage(string code, HttpContext context)
 {
 System.IO.MemoryStream ms = new System.IO.MemoryStream();
 Bitmap image = this.CreateImageCode(code);
 
 image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
 
 context.Response.ClearContent();
 context.Response.ContentType = "image/Jpeg";
 context.Response.BinaryWrite(ms.GetBuffer());
 
 ms.Close();
 ms = null;
 image.Dispose();
 image = null;
 }
 #endregion
 
 #region 生成随机字符码
 public string CreateVerifyCode(int codeLen)
 {
 if (codeLen == 0)
 {
  codeLen = Length;
 }
 
 string[] arr = CodeSerial.Split(',');
 
 string code = "";
 
 int randValue = -1;
 
 Random rand = new Random(unchecked((int)DateTime.Now.Ticks));
 
 for (int i = 0; i < codeLen; i++)
 {
  randValue = rand.Next(0, arr.Length - 1);
 
  code += arr[randValue];
 }
 
 return code;
 }
 public string CreateVerifyCode()
 {
 return CreateVerifyCode(0);
 }
 #endregion
 
}

一年一度的抢票热潮又开始了,希望大家都能顺利买到回家的火车篇,回家过年,突然感觉有点年味了,一年又一年,时间都去哪了,小小的感慨一下……

言归正传,这就是为大家分享的C#验证码程序,和12306验证码差多了,不过也是小编的学习收获吧!大家也可以结合下面这两篇文章进行学习:

《12306动态验证码启发之ASP.NET实现动态GIF验证码(附源码)》

《12306验证码破解思路分享》

希望本文所述对大家学习验证码技术有所帮助。

标签:

相关文章

热门资讯

yue是什么意思 网络流行语yue了是什么梗
yue是什么意思 网络流行语yue了是什么梗 2020-10-11
2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全
2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全 2019-12-26
背刺什么意思 网络词语背刺是什么梗
背刺什么意思 网络词语背刺是什么梗 2020-05-22
2021年耽改剧名单 2021要播出的59部耽改剧列表
2021年耽改剧名单 2021要播出的59部耽改剧列表 2021-03-05
苹果12mini价格表官网报价 iPhone12mini全版本价格汇总
苹果12mini价格表官网报价 iPhone12mini全版本价格汇总 2020-11-13
返回顶部