首页 > 代码库 > 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---前台系统图片验证码心得