首页 > 代码库 > WebSite---前台系统图片验证码心得

WebSite---前台系统图片验证码心得

        背景: 因为移动端APP和Msite手机注册发送短信验证码没有添加图片验证码功能。公司的短信接口被恶意刷取。所以我们就觉得在移动端添加一个图片验证码功能。分享一下大体实现方式思路。PS demo是自己写的。跟公司代码还是有很大差距的。

   一. 图片验证码第一版   

      1. 建立图片验证码 ValidationCodeHelper

          1.1 填写方法生成对应的.验证码: 默认是4位数字

 1         private static char[] _constant = {   2         0,1,2,3,4,5,6,7,8,9,   3         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,    4         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    5          }; 6  7         public static string CreateValidateCode(int length = 4, bool isNum = true) 8         { 9             var sb = new StringBuilder();10             var constant = isNum ? _constant.Take(10).ToArray() : _constant;11             var constant_count = constant.Count();12             Random rd = new Random();13             for (var index = 0; index < length; index++)14             {15                 sb.Append(constant[rd.Next(constant_count)]);16             }17             return sb.ToString();18         }

            1.2 通过验证码生成图片流, 此代码是从其他博友那里Copy过来的。自己对图片方面不擅长

 1 public static byte[] GetImage(string code) 2         { 3             Bitmap image = new Bitmap((int)Math.Ceiling(code.Length * 16.0), 27); 4             Graphics g = Graphics.FromImage(image); 5             try 6             { 7                 Random random = new Random(); 8                 g.Clear(Color.Gray); 9                 for (int i = 0; i < 25; i++)10                 {11                     int x1 = random.Next(image.Width);12                     int x2 = random.Next(image.Width);13                     int y1 = random.Next(image.Height);14                     int y2 = random.Next(image.Height);15                     g.DrawLine(new Pen(Color.Silver), x1, x2, y1, y2);16                 }17                 Font font = new Font("Arial", 13, (FontStyle.Bold | FontStyle.Italic));18                 LinearGradientBrush brush = new LinearGradientBrush(new Rectangle(0, 0, image.Width, image.Height), Color.Blue, Color.DarkRed, 1.2f, true);19                 g.DrawString(code, font, brush, 3, 2);20                 for (int i = 0; i < 100; i++)21                 {22                     int x = random.Next(image.Width);23                     int y = random.Next(image.Height);24                     image.SetPixel(x, y, Color.FromArgb(random.Next()));25                 }26                 g.DrawRectangle(new Pen(Color.Silver), 0, 0, image.Width - 1, image.Height - 1);27                 MemoryStream stream = new MemoryStream();28                 image.Save(stream, ImageFormat.Jpeg);29                 return stream.ToArray();30             }31             catch (Exception ex)32             {33                 return null;34             }35             finally36             {37                 g.Dispose();38                 image.Dispose();39             }40         }

        2. 封装一个简单的CookieHelper类型主要是对Cookie进行加密。只是简单封装, 没有对CookieHelper添加泛型,未支持Object处理。公司里面的CookieHelper库更强大。可是不能分享代码出来。所以自己简单的写了一个。

 1     public class CookieHelper 2     { 3  4         #region 字符串加密解密 5  6         private static string _MD5 = "8ff0c65d-a2ed-4e1e-af85-690c08b8d039"; 7  8         private static string Decrypt(string cipherString) 9         {10             byte[] keyArray;11             byte[] toEncryptArray = Convert.FromBase64String(cipherString);12             MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();13             keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(_MD5));14             hashmd5.Clear();15 16             TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();17             tdes.Key = keyArray;18             tdes.Mode = CipherMode.ECB;19             tdes.Padding = PaddingMode.PKCS7;20             ICryptoTransform cTransform = tdes.CreateDecryptor();21             byte[] resultArray = cTransform.TransformFinalBlock(22                                  toEncryptArray, 0, toEncryptArray.Length);              23             tdes.Clear();24             return UTF8Encoding.UTF8.GetString(resultArray);25         }26 27         private static string Encrypt(string toEncrypt)28         {29             byte[] keyArray;30             byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);31             MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();32             keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(_MD5));33             hashmd5.Clear();34 35             TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();36             tdes.Key = keyArray;37             tdes.Mode = CipherMode.ECB;38             tdes.Padding = PaddingMode.PKCS7;39 40             ICryptoTransform cTransform = tdes.CreateEncryptor();41             byte[] resultArray =42               cTransform.TransformFinalBlock(toEncryptArray, 0,43               toEncryptArray.Length);44             tdes.Clear();45             return Convert.ToBase64String(resultArray, 0, resultArray.Length);46         }47 48 49         #endregion50 51 52         #region Cookie53 54         public static void SaveCookie(string name, string value, int expiredSecond = 0)55         {56             var encryptStr = Encrypt(value);57             var collection = HttpContext.Current.Response.Cookies;58             collection.Add(new HttpCookie(name)59             {60                 Value =http://www.mamicode.com/ encryptStr,61                 Expires = expiredSecond > 0 ? System.DateTime.Now.AddSeconds(expiredSecond) : System.DateTime.MaxValue62             });63         }64 65         public static string GetCookie(string name)66         {67             var cookie = HttpContext.Current.Request.Cookies.Get(name);68             if (cookie == null)69             {70                 return null;71             }72             else73             {74                 return Decrypt(cookie.Value);75             }76         }77 78         #endregion79     }

       3. Controller新增图片服务。设置图片的Cookie有效期是一分钟

 1 public class HomeController : Controller 2     { 3         public ActionResult Index() 4         { 5             return View(); 6         } 7  8         public FileContentResult ImageValidator() 9         {10             var code = ValidationCodeHelper.CreateValidateCode();11             CookieHelper.SaveCookie("PicCode", code, 60);12             var picByte = ValidationCodeHelper.GetImage(code);13             return File(picByte, "image/jpeg "); 14         }15 16         /// <summary>17         /// 检查图片验证码是否正确18         /// </summary>19         /// <param name="code"></param>20         /// <returns></returns>21         public ActionResult CheckPicCode(string code)22         {23             var cookieCode = CookieHelper.GetCookie("PicCode");24             if (string.IsNullOrWhiteSpace(cookieCode))25             {26                 return Json("验证码过期",JsonRequestBehavior.AllowGet);27             }28             if (code.Trim().ToUpper() == cookieCode.ToUpper())29             {30                 return Json("验证码正确",JsonRequestBehavior.AllowGet);31             }32             else33             {34                 return Json("验证码错误",JsonRequestBehavior.AllowGet);35             }36         }37     }

         4.前台页面. 通过修改img的src链接,来实现点击刷新图片.

 1 <head> 2     <title></title> 3     <script src=http://www.mamicode.com/"https://cdn.static.runoob.com/libs/jquery/1.10.2/jquery.min.js"></script> 4 </head> 5 <body> 6     <input type="text" id="inpCode" /> 7     <img id="picCode" src=http://www.mamicode.com/"/Home/ImageValidator" /> 8     <button id="btnCheck" >校验</button> 9 </body>10 </html>11 <script>12 13     $(function () {14 15         $("#picCode").on(click, function () {16             $(this).attr(src, "/Home/ImageValidator?v=" + new Date().getTime());17         })18 19         $("#btnCheck").on(click, function () {20             $.ajax({21                 type: get,22                 url: "/Home/CheckPicCode",23                 data: {24                     code:$("#inpCode").val()25                 },26                 success: function (data) {27                     alert(data);28                 }29             })30         })31 32     })33 34 </script>

          5. 第一版基本代码实现了,点击图片刷新验证码,图片验证码有效期是一分钟.

  一分钟内

  技术分享

 

一分钟后,验证码过期了

 技术分享

              6.大家看上面两张图以为验证码OK了。的确。正常网站使用是OK的。因为我们设置了验证码的有效时间是一分钟。那我们看看Fiddler里面的效果。

       当我面在Fiddler里面模拟的时候Cookie的过期时间是没有的。也就是如果客户端用户抓取了PicCode的Cookie后。自己构建请求的话。Cookie是不会失效的。

        技术分享

 

     技术分享

    二. 图片验证码改版。

         从上面看来 直接设置Cookie的过期时间是不行的。那我们只能在Cookie存储Value上修改了。来看看我们代码实现方式。我们将过期时间的ticks和验证码字符串同时加密存储在了Cookie中。

13 14         /// <summary>15         /// 构建图片Cookie字符串,code和过期见时间用逗号隔开16         /// </summary>17         public static string BuildValidateCodeStorage(string code, int expiredSeconds = 60)18         {19             return string.Format("{0},{1}", code, System.DateTime.Now.AddSeconds(expiredSeconds).Ticks);20         }21 22         /// <summary>23         /// 解析图片验证码Cookie24         /// </summary>25         public static string AnysisValidateCode(string codeStorage)26         {27             if (string.IsNullOrWhiteSpace(codeStorage))28             {29                 return null;30             }31             else32             {33                 var vals = codeStorage.Split(,);34                 if (vals.Count() != 2)35                 {36                     return null;37                 }38                 else39                 {40                     long ticks = 0;41                     long.TryParse(vals[1], out ticks);42                     if (ticks > System.DateTime.Now.Ticks)43                     {44                         return vals[0];45                     }46                     else47                     {48                         return null;49                     }50                 }51             }52         }

      三.总结

    这个是我们暂时想到的图片验证码实现方案。不知道其他博友公司是如何实现的。希望大家也可以分享一下。

           http://files.cnblogs.com/files/FourLeafCloverZc/CSharp.zip

                 

WebSite---前台系统图片验证码心得