构建一个.net的干货类库,以便于快速的开发 - 验证码
一个验证码对于一个网站的作用不言而喻,而随着技术的发展验证码的种类也开始多了起来,发展至今很多网站已经不再使用一种验证码,为满足需求程序猿就要写很多的方法来适应需求,今天我就来介绍我之前收集到的验证码的方法写成的一个帮助类,来解决我们日常开发当中的验证码需求问题。
帮助类中验证码是以byte[]的格式返回的,方便使用。
英文字符验证码
1 /// <summary> 2 /// 英文字符验证码 3 /// </summary> 4 /// <param name="Code">传出验证码</param> 5 /// <param name="CodeLength">验证码字符</param> 6 /// <returns></returns> 7 public static byte[] GraphCode(out string Code,int CodeLength) 8 { 9 int Width = 80;//默认为100 10 int Height = 30;//默认为40 11 int FontSize = 20;//默认为20 12 byte[] bytes = GraphCode(out Code, CodeLength, Width, Height, FontSize); 13 return bytes; 14 } 15 16 /// <summary> 17 /// 产生图形验证码。 18 /// </summary> 19 /// <param name="Code">传出验证码。</param> 20 /// <param name="CodeLength">验证码字符。</param> 21 /// <param name="Width"></param> 22 /// <param name="Height"></param> 23 /// <param name="FontSize"></param> 24 /// <returns></returns> 25 public static byte[] GraphCode(out string Code, int CodeLength, int Width, int Height, int FontSize) 26 { 27 string code = string.Empty; 28 String sCode = String.Empty; 29 //顏色列表,用于验证码、噪线、噪点 30 Color[] oColors ={ 31 Color.Black, 32 Color.Red, 33 Color.Blue, 34 Color.Green, 35 Color.Orange, 36 Color.Brown, 37 Color.Brown, 38 Color.DarkBlue 39 }; 40 //字体列表,用于验证码 41 string[] oFontNames = { "Times New Roman", "MS Mincho", "Book Antiqua", "Gungsuh", "PMingLiU", "Impact" }; 42 //验证码的字元集 43 char[] oCharacter = 44 { 45 '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', 46 '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' 47 }; 48 Random oRnd = new Random(); 49 Bitmap oBmp = null; 50 Graphics oGraphics = null; 51 int N1 = 0; 52 //生成验证码字串 53 for (N1 = 0; N1 <= CodeLength - 1; N1++) 54 { 55 sCode += oCharacter[oRnd.Next(oCharacter.Length)]; 56 } 57 oBmp = new Bitmap(Width, Height); 58 oGraphics = Graphics.FromImage(oBmp); 59 oGraphics.Clear(Color.White); 60 try 61 { 62 oGraphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; 63 Font f = new System.Drawing.Font("宋体", FontSize, (System.Drawing.FontStyle.Bold)); 64 // 前景色 65 Brush b = new System.Drawing.SolidBrush(Color.Black); 66 // 背景色 67 oGraphics.Clear(Color.White); 68 // 填充文字 69 for (int i = 0; i < sCode.Length; i++) 70 { 71 oGraphics.DrawString(sCode[i].ToString(), f, b, new Rectangle(i * (FontSize - 2), 3, (FontSize - 2), Height)); 72 } 73 // 随机线条 74 Pen linePen = new Pen(Color.Gray, 0); 75 Random rand = new Random(); 76 for (int i = 0; i < 3; i++) 77 { 78 int x1 = rand.Next(oBmp.Width); 79 int y1 = rand.Next(oBmp.Height); 80 int x2 = rand.Next(oBmp.Width); 81 int y2 = rand.Next(oBmp.Height); 82 oGraphics.DrawLine(linePen, x1, y1, x2, y2); 83 } 84 85 // 随机点 86 for (int i = 0; i < 30; i++) 87 { 88 int x = rand.Next(oBmp.Width); 89 int y = rand.Next(oBmp.Height); 90 oBmp.SetPixel(x, y, Color.FromArgb(rand.Next(250), rand.Next(250), rand.Next(250))); 91 } 92 93 Code = sCode; 94 //保存图片数据 95 MemoryStream stream = new MemoryStream(); 96 oBmp.Save(stream, ImageFormat.Jpeg); 97 //输出图片流 98 return stream.ToArray(); 99 } 100 finally 101 { 102 oGraphics.Dispose(); 103 } 104 }
验证码中的字元集是可以改变的,可以去掉一些容易混淆的字元,我这里使用了全部的字元
数字字符验证码
1 /// <summary> 2 /// 纯数字图形验证码 3 /// </summary> 4 /// <param name="Code">传出验证码</param> 5 /// <param name="CodeLength">验证码字符</param> 6 /// <returns></returns> 7 public static byte[] NumCode(out string Code, int CodeLength) 8 { 9 Code = CreateValidateCode(CodeLength); 10 byte[] bytes = CreateValidateGraphic(Code); 11 return bytes; 12 } 13 /// <summary> 14 /// 生成验证码 15 /// </summary> 16 /// <param name="CodeLength">指定验证码的长度</param> 17 /// <returns></returns> 18 private static string CreateValidateCode(int CodeLength) 19 { 20 int[] randMembers = new int[CodeLength]; 21 int[] validateNums = new int[CodeLength]; 22 string validateNumberStr = ""; 23 //生成起始序列值 24 int seekSeek = unchecked((int)DateTime.Now.Ticks); 25 Random seekRand = new Random(seekSeek); 26 int beginSeek = (int)seekRand.Next(0, Int32.MaxValue - CodeLength * 10000); 27 int[] seeks = new int[CodeLength]; 28 for (int i = 0; i < CodeLength; i++) 29 { 30 beginSeek += 10000; 31 seeks[i] = beginSeek; 32 } 33 //生成随机数字 34 for (int i = 0; i < CodeLength; i++) 35 { 36 Random rand = new Random(seeks[i]); 37 int pownum = 1 * (int)Math.Pow(10, CodeLength); 38 randMembers[i] = rand.Next(pownum, Int32.MaxValue); 39 } 40 //抽取随机数字 41 for (int i = 0; i < CodeLength; i++) 42 { 43 string numStr = randMembers[i].ToString(); 44 int numCodeLength = numStr.Length; 45 Random rand = new Random(); 46 int numPosition = rand.Next(0, numCodeLength - 1); 47 validateNums[i] = Int32.Parse(numStr.Substring(numPosition, 1)); 48 } 49 //生成验证码 50 for (int i = 0; i < CodeLength; i++) 51 { 52 validateNumberStr += validateNums[i].ToString(); 53 } 54 return validateNumberStr; 55 } 56 57 58 /// <summary> 59 /// 创建验证码的图片 60 /// </summary> 61 /// <param name="validateCode">验证码</param> 62 private static byte[] CreateValidateGraphic(string validateCode) 63 { 64 Bitmap image = new Bitmap((int)Math.Ceiling(validateCode.Length * 12.0), 22); 65 Graphics g = Graphics.FromImage(image); 66 try 67 { 68 //生成随机生成器 69 Random random = new Random(); 70 //清空图片背景色 71 g.Clear(Color.White); 72 //画图片的干扰线 73 for (int i = 0; i < 25; i++) 74 { 75 int x1 = random.Next(image.Width); 76 int x2 = random.Next(image.Width); 77 int y1 = random.Next(image.Height); 78 int y2 = random.Next(image.Height); 79 g.DrawLine(new Pen(Color.Silver), x1, y1, x2, y2); 80 } 81 Font font = new Font("Arial", 12, (FontStyle.Bold | FontStyle.Italic)); 82 LinearGradientBrush brush = new LinearGradientBrush(new Rectangle(0, 0, image.Width, image.Height), 83 Color.Blue, Color.DarkRed, 1.2f, true); 84 g.DrawString(validateCode, font, brush, 3, 2); 85 //画图片的前景干扰点 86 for (int i = 0; i < 100; i++) 87 { 88 int x = random.Next(image.Width); 89 int y = random.Next(image.Height); 90 image.SetPixel(x, y, Color.FromArgb(random.Next())); 91 } 92 //画图片的边框线 93 g.DrawRectangle(new Pen(Color.Silver), 0, 0, image.Width - 1, image.Height - 1); 94 //保存图片数据 95 MemoryStream stream = new MemoryStream(); 96 image.Save(stream, ImageFormat.Jpeg); 97 //输出图片流 98 return stream.ToArray(); 99 } 100 finally 101 { 102 g.Dispose(); 103 image.Dispose(); 104 } 105 }
数字与字符混合验证码
1 /// <summary> 2 /// 生成随机字符串 3 /// </summary> 4 /// <param name="NumCount"></param> 5 /// <returns></returns> 6 private static string CreateRandomNum(int NumCount) 7 { 8 char[] allCharArray = 9 { 10 '1','2','3','4','5','6','7','8','9', 11 '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', 12 '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' 13 }; 14 string randomNum = ""; 15 int temp = -1;//记录上次随机数的数值,尽量避免产生几个相同的随机数 16 Random rand = new Random(); 17 for (int i = 0; i < NumCount; i++) 18 { 19 if (temp != -1) 20 { 21 rand = new Random(i * temp * ((int)DateTime.Now.Ticks)); 22 } 23 int t = rand.Next(35); 24 if (temp == t) 25 { 26 return CreateRandomNum(NumCount); 27 } 28 temp = t; 29 randomNum += allCharArray[t]; 30 } 31 return randomNum; 32 } 33 34 /// <summary> 35 /// 数字和字符混合验证码 36 /// </summary> 37 /// <param name="Code">传出字符</param> 38 /// <param name="NumCount">字节长度</param> 39 /// <param name="Width">图片宽度</param> 40 /// <param name="Height">图片长度</param> 41 /// <param name="FontSize">文字大小</param> 42 /// <returns></returns> 43 public static byte[] GNCode(out string Code, int NumCount, int Width, int Height, int FontSize) 44 { 45 string validateNum = CreateRandomNum(NumCount); 46 Code = null; 47 if (validateNum == null || validateNum.Trim() == String.Empty) 48 return null; 49 //生成Bitmap图像 50 System.Drawing.Bitmap image = new System.Drawing.Bitmap(Width, Height); 51 Graphics g = Graphics.FromImage(image); 52 53 try 54 { 55 //生成随机生成器 56 Random random = new Random(); 57 58 //清空图片背景色 59 g.Clear(Color.White); 60 61 g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; 62 Font f = new System.Drawing.Font("宋体", FontSize, (System.Drawing.FontStyle.Bold)); 63 // 前景色 64 Brush b = new System.Drawing.SolidBrush(Color.Black); 65 // 背景色 66 g.Clear(Color.White); 67 // 填充文字 68 for (int i = 0; i < validateNum.Length; i++) 69 { 70 g.DrawString(validateNum[i].ToString(), f, b, new Rectangle(i * (FontSize - 2), 3, (FontSize - 2), Height)); 71 } 72 // 随机线条 73 Pen linePen = new Pen(Color.Gray, 0); 74 Random rand = new Random(); 75 for (int i = 0; i < 3; i++) 76 { 77 int x1 = rand.Next(image.Width); 78 int y1 = rand.Next(image.Height); 79 int x2 = rand.Next(image.Width); 80 int y2 = rand.Next(image.Height); 81 g.DrawLine(linePen, x1, y1, x2, y2); 82 } 83 84 // 随机点 85 for (int i = 0; i < 30; i++) 86 { 87 int x = rand.Next(image.Width); 88 int y = rand.Next(image.Height); 89 image.SetPixel(x, y, Color.FromArgb(rand.Next(250), rand.Next(250), rand.Next(250))); 90 } 91 92 Code = validateNum; 93 94 //保存图片数据 95 MemoryStream stream = new MemoryStream(); 96 image.Save(stream, ImageFormat.Jpeg); 97 //输出图片流 98 return stream.ToArray(); 99 } 100 finally 101 { 102 g.Dispose(); 103 image.Dispose(); 104 } 105 }
数学算式验证码
1 /// <summary> 2 /// 数学算式的验证码 3 /// </summary> 4 /// <param name="Code"></param> 5 /// <returns></returns> 6 public static byte[] MathVerifyCode(out int Code) 7 { 8 int mathResult = 0; 9 string expression = null; 10 11 Random rnd = new Random(); 12 13 ////生成3个10以内的整数,用来运算 14 int operator1 = rnd.Next(0, 10); 15 int operator2 = rnd.Next(10, 100); 16 int operator3 = rnd.Next(0, 10); 17 18 ////随机组合运算顺序,只做 + 和 - 运算 19 switch (rnd.Next(0, 3)) 20 { 21 case 0: 22 mathResult = operator1 + operator2 + operator3; 23 expression = string.Format("{0} + {1} + {2} = ?", operator1, operator2, operator3); 24 break; 25 case 1: 26 mathResult = operator2 - operator1 + operator3; 27 expression = string.Format("{0} - {1} + {2} = ?", operator2, operator1, operator3); 28 break; 29 default: 30 mathResult = operator2 + operator1 - operator3; 31 expression = string.Format("{0} + {1} - {2} = ?", operator2, operator1, operator3); 32 break; 33 } 34 Code = mathResult; 35 using (Bitmap bmp = new Bitmap(150, 25)) 36 { 37 using (Graphics graph = Graphics.FromImage(bmp)) 38 { 39 graph.Clear(Color.FromArgb(232, 238, 247)); ////背景色,可自行设置 40 41 ////画噪点 42 for (int i = 0; i <= 128; i++) 43 { 44 graph.DrawRectangle( 45 new Pen(Color.FromArgb(rnd.Next(0, 255), rnd.Next(0, 255), rnd.Next(0, 255))), 46 rnd.Next(2, 128), 47 rnd.Next(2, 38), 48 1, 49 1); 50 } 51 52 ////输出表达式 53 for (int i = 0; i < expression.Length; i++) 54 { 55 graph.DrawString(expression.Substring(i, 1), 56 new Font(FontFamily.GenericSansSerif, 12, FontStyle.Bold), 57 new SolidBrush(Color.FromArgb(rnd.Next(255), rnd.Next(128), rnd.Next(255))), 58 5 + i * 10, 59 rnd.Next(1, 5)); 60 } 61 62 ////画边框,不需要可以注释掉 63 graph.DrawRectangle(new Pen(Color.Firebrick), 0, 0, 150 - 1, 25 - 1); 64 } 65 66 MemoryStream stream = new MemoryStream(); 67 bmp.Save(stream, ImageFormat.Jpeg); 68 //输出图片流 69 return stream.ToArray(); 70 } 71 }
数学算式验证码里面的算式结构是可以改成更复杂的,不过个人觉得加减法已经可以满足日常需求
使用方式
以ASP.NET MVC为例,使用方式很简单,写一个方法,以图片文件的形式输出
1 /// <summary> 2 /// 验证码 3 /// </summary> 4 /// <returns></returns> 5 public virtual ActionResult VerifyImage() 6 { 7 string Code = ""; 8 byte[] bytes = CodeHelper.GNCode(out Code, 4, 80, 26, 20); 9 Session["Code"] = Code; 10 return File(bytes, @"image/jpeg"); 11 }
这里的CodeHelper就是我们写好的验证码帮助类,直接调用
前端放一张图片来显示验证码
<img src="@Url.Action("VerifyImage")" id="VerifyImage" title="点击换一个">
应用截图