C#實(shí)現(xiàn)圖像選擇驗(yàn)證碼的示例代碼
開發(fā)環(huán)境:C#,VS2019,.NET Core 3.1,ASP.NET Core
前幾年使用12306購(gòu)買火車票時(shí)使用過這種驗(yàn)證碼,根據(jù)文字描述選擇對(duì)應(yīng)的圖片,文字是隨機(jī)的,圖片也是隨機(jī)的。
1、建立一個(gè)驗(yàn)證碼控制器
新建兩個(gè)方法Create和Check,Create用于創(chuàng)建驗(yàn)證碼,Check用于驗(yàn)證它是否有效。
聲明一個(gè)靜態(tài)類變量存放列表,列表中存放包含令牌和驗(yàn)證碼的對(duì)象。
/// <summary> /// 返回多張圖片,一個(gè)文字和令牌. /// </summary> /// <returns></returns> public string Create() { try { VCodeImageSelectModel model = new VCodeImageSelectModel(); model.id = Guid.NewGuid().ToString(); // 生成令牌 var vcode = VCodeImageSelectModel.GetVCode(); // 生成驗(yàn)證碼 model.code.text = vcode.Item1; model.code.image = vcode.Item4; _list.Add(model); // 返回結(jié)果 var image = VCodeImageSelectModel.DrawImage(model.code.text); var base64 = VCodeImageSelectModel.BitmapToBase64Str(image); var images = vcode.Item2; VCodeImageSelectController_Create_Receive result = new VCodeImageSelectController_Create_Receive(); result.code = "0"; result.data.id = model.id; result.data.img = VCodeImageSelectModel.BitmapToBase64Str(images); result.data.img_index = vcode.Item3; result.data.img_text = base64; var json = JsonConvert.SerializeObject(result); return json; } catch (Exception ex) { _logger.LogWarning(exception: ex, message: ex.Message); VCodeImageSelectController_Create_Receive result = new VCodeImageSelectController_Create_Receive(); result.code = "999999"; result.msg = "系統(tǒng)異常"; var json = JsonConvert.SerializeObject(result); return json; } } /// <summary> /// 檢查驗(yàn)證碼是否有效 /// </summary> /// <param name="id">令牌.</param> /// <param name="code">驗(yàn)證碼.</param> /// <returns></returns> [HttpGet] public string Check(string id, string code) { try { ReceiveObject result = new ReceiveObject(); var list_result = code.Split(',').ToList(); // 拆分驗(yàn)證碼為數(shù)組 var list_temp = new List<string>(); if(_list.Find(m => m.id == id) == null) { result.code = "999999"; result.msg = "系統(tǒng)異常"; var json = JsonConvert.SerializeObject(result); return json; } _list.Find(m => m.id == id).code.image.ForEach(m => { // 復(fù)制數(shù)組,避免重復(fù)提交后仍然能獲取到完整的數(shù)據(jù) list_temp.Add(m); }); var index = _list.FindIndex(m => { var flag = false; for (int i = 0; i < list_result.Count; i++) { var item = list_result[i]; flag = m.code.image.Exists(m => m.Equals(item)); if(flag == false) { // 選中了錯(cuò)誤的 return false; } else { // 每次將選中的項(xiàng)刪除,這樣最終得到的數(shù)組應(yīng)該是空的 list_temp.Remove(item); } } if(list_temp.Count > 0) { // 未全部選中 return false; } if (m.id.Equals(id) && flag) { // 通過 return true; } return false; }); if (index >= 0) { _list.RemoveAt(index); result.code = "0"; result.msg = "驗(yàn)證成功"; var json = JsonConvert.SerializeObject(result); return json; } else { result.code = "1"; result.msg = "驗(yàn)證失敗"; var json = JsonConvert.SerializeObject(result); return json; } } catch (Exception ex) { _logger.LogError(exception: ex, message: ex.Message); ReceiveObject result = new ReceiveObject(); result.code = "999999"; result.msg = "系統(tǒng)異常"; var json = JsonConvert.SerializeObject(result); return json; } }
2、建立一個(gè)驗(yàn)證碼模型
驗(yàn)證碼模型類包括:令牌和驗(yàn)證碼屬性。
再創(chuàng)建一個(gè)類存放GetVCode方法返回的對(duì)象包括:圖片的類型(它又叫文字描述)的圖片,圖片數(shù)組,圖片對(duì)應(yīng)的序號(hào),該類型的圖片對(duì)應(yīng)的序號(hào)。
DrawImage方法生成圖片的類型(它又叫文字描述)的圖片
GetVCodeList方法生成圖片數(shù)組,圖片對(duì)應(yīng)的序號(hào),該類型的圖片對(duì)應(yīng)的序號(hào)。
BitmapToBase64Str方法用來將圖片對(duì)象轉(zhuǎn)成Base64字符串
/// <summary> /// 獲取隨機(jī)的文字和驗(yàn)證碼. /// </summary> /// <returns> /// 第一個(gè)參數(shù) - 圖片的類型(文字描述) /// 第二個(gè)參數(shù) - 圖片數(shù)組,用來顯示圖片 /// 第三個(gè)參數(shù) - 圖片對(duì)應(yīng)的序號(hào) /// 第四個(gè)參數(shù) - 該類型的圖片對(duì)應(yīng)的序號(hào) /// </returns> public static Tuple<string, List<Bitmap>, List<string>, List<string>> GetVCode() { Random random = new Random(); var type = random.Next(1, List_Text.Count + 1).ToString(); var typeName = List_Text.ElementAt(Convert.ToInt32(type) - 1); var result = GetVCodeList(type); return new Tuple<string, List<Bitmap>, List<string>, List<string>>(typeName, result.Item1, result.Item2, result.Item3); } /// <summary> /// 獲取隨機(jī)的驗(yàn)證碼. /// </summary> /// <param name="type">圖片的類型.</param> /// <returns> /// 第一個(gè)參數(shù) - 圖片數(shù)組,用來顯示圖片 /// 第二個(gè)參數(shù) - 圖片對(duì)應(yīng)的序號(hào) /// 第三個(gè)參數(shù) - 該類型的圖片對(duì)應(yīng)的序號(hào) /// </returns> private static Tuple<List<Bitmap>, List<string>, List<string>> GetVCodeList(string type) { // 這里的隨機(jī)碼是一個(gè)有四個(gè)元素的數(shù)組,如果發(fā)現(xiàn)沒有生成指定類型的,就重新生成. var list_files = Directory.GetFiles(PathHelper.Path + @"Images\imageSelect"); var count = list_files.Count(); List<string> list_index = new List<string>(); var list_fileName = new List<string>(); List<string> list_selectedIndex = new List<string>(); Random random = new Random(); while (true) { while (true) { var index = random.Next(0, count).ToString(); if (list_index.Exists(m => m.Equals(index)) == false) { list_index.Add(index); var temp = list_files.ElementAt(Convert.ToInt32(index)).Replace(PathHelper.Path + @"Images\imageSelect", ""); // 只保留文件名,去掉路徑 list_fileName.Add(temp); if(temp.Replace("\\img", "").Substring(0, 1) == type) { list_selectedIndex.Add(index); } } if (list_index.Count >= 4) { break; } } // 判斷是否至少生成了一個(gè)指定類型的圖片 var flag = false; flag = list_fileName.Exists(m => { if (m.Contains("img" + type)) { return true; } return false; }); if (flag == false) { list_index.Clear(); list_fileName.Clear(); list_selectedIndex.Clear(); continue; } else { // 至少生成了一個(gè)指定類型的圖片 break; } } // 加載圖片 List<Bitmap> list_image = new List<Bitmap>(); for (int i = 0; i < list_fileName.Count; i++) { var image = Image.FromFile(string.Format(@"{0}Images\imageSelect\{1}", PathHelper.Path, list_fileName.ElementAt(i))); list_image.Add((Bitmap)image); } return new Tuple<List<Bitmap>, List<string>, List<string>>(list_image, list_index, list_selectedIndex); } /// <summary> /// 將圖片對(duì)象轉(zhuǎn)成Base64的字符串. /// </summary> /// <param name="bitmap"></param> /// <returns></returns> public static List<string> BitmapToBase64Str(List<Bitmap> bitmap) { List<string> list = new List<string>(); for (int i = 0; i < bitmap.Count; i++) { using (MemoryStream memoryStream = new MemoryStream()) { bitmap.ElementAt(i).Save(memoryStream, ImageFormat.Jpeg); byte[] bytes = memoryStream.ToArray(); list.Add(Convert.ToBase64String(memoryStream.ToArray())); } } return list; } /// <summary> /// 將圖片對(duì)象轉(zhuǎn)成Base64的字符串. /// </summary> /// <param name="bitmap"></param> /// <returns></returns> public static string BitmapToBase64Str(Bitmap bitmap) { using (MemoryStream memoryStream = new MemoryStream()) { bitmap.Save(memoryStream, ImageFormat.Jpeg); byte[] bytes = memoryStream.ToArray(); return Convert.ToBase64String(memoryStream.ToArray()); } } /// <summary> /// 繪制驗(yàn)證碼的圖片. /// </summary> /// <param name="code"></param> /// <returns></returns> public static Bitmap DrawImage(string code) { Color[] list_color = { Color.FromArgb(240, 230, 140), // 黃褐色(亮) Color.FromArgb(138, 54, 15), // 黃褐色(暗) Color.FromArgb(51, 161, 201), // 藍(lán)色(亮) Color.FromArgb(25, 25, 112), // 藍(lán)色(暗) Color.FromArgb(192, 192, 192), // 灰白(亮) Color.FromArgb(128, 128, 105), // 灰白(暗) }; Random random = new Random(); // 創(chuàng)建畫板 Bitmap bitmap = new Bitmap(85, 50); // 創(chuàng)建畫筆 Graphics grp = Graphics.FromImage(bitmap); grp.Clear(Color.White); // 設(shè)置背景色為白色 // 繪制噪點(diǎn) for (int i = 0; i < random.Next(30, 40); i++) { int x = random.Next(bitmap.Width); int y = random.Next(bitmap.Height); grp.DrawLine(new Pen(Color.LightGray, 1), x, y, x + 1, y); } // 繪制隨機(jī)的線條 grp.DrawLine( new Pen(list_color[random.Next(list_color.Length)], random.Next(3)), new Point(random.Next(bitmap.Width / 2), random.Next(bitmap.Height / 2)), new Point(bitmap.Width / 2 + random.Next(bitmap.Width / 2), bitmap.Height / 2 + random.Next(bitmap.Height / 2)) ); // 繪制驗(yàn)證碼 for (int i = 0; i < code.Length; i++) { var item = code[i]; grp.DrawString(item.ToString(), new Font(FontFamily.GenericSansSerif, 25, FontStyle.Bold), new SolidBrush(list_color[random.Next(list_color.Length)]), x: (75 / 2) * i, y: random.Next(5)); } // 在驗(yàn)證碼上繪制噪點(diǎn) for (int i = 0; i < random.Next(15, 25); i++) { int x = random.Next(bitmap.Width); int y = random.Next(bitmap.Height); grp.DrawLine(new Pen(list_color[random.Next(list_color.Length)], 1), x, y, x + 1, y); } // 繪制隨機(jī)的線條 grp.DrawLine( new Pen(list_color[random.Next(list_color.Length)], random.Next(3)), new Point(random.Next(bitmap.Width / 2), random.Next(bitmap.Height / 2)), new Point(bitmap.Width / 2 + random.Next(bitmap.Width / 2), bitmap.Height / 2 + random.Next(bitmap.Height / 2)) ); return bitmap; }
3、新建一個(gè)視圖文件
引入jquery,css文件,js方法中添加幾個(gè)事件 - 點(diǎn)擊圖片,提交按鈕。頁(yè)面首次加載時(shí)調(diào)用控制器的Create方法獲取圖片和令牌。
<link href="~/css/image_select.css" rel="external nofollow" rel="stylesheet" /> <!-- 展示驗(yàn)證碼 --> <div class="container"> <div class="main"> <div> 請(qǐng)選擇所有的<img id="backTextImage" src="" alt=""> </div> @for (int i = 1; i < 5; i++) { @if (i % 2 == 1) { <div style="float:left;"> <div> <img id="backImage@(i)" + src="" class="img_check" checked="0"> </div> <div id="div_icon@(i)" class="divIconClass"> <img id="imgIcon@(i)" src="~/img/Select.png" class="imgIconClass"/> </div> </div> } else { <div> <div> <img id="backImage@(i)" + src="" class="img_check" checked="0"> </div> <div id="div_icon@(i)" class="divIconClass"> <img id="imgIcon@(i)" src="~/img/Select.png" class="imgIconClass"/> </div> </div> } } </div> <div style="position:relative;left:20px;"> <input type="button" value="提交" id="button_submit" /> </div> </div> <script src="~/lib/jquery/dist/jquery.js"></script> <script src="~/js/image_select.js"></script>
* { margin: 0; padding: 0; } .main { position: relative; margin-left: 20px; margin-top: 20px; width: 300px; background-color: white; } .img_check { width: 100px; height: 100px; } #div_icon1 { bottom: 30px; left: 70px; } #div_icon2 { bottom: 56px; left: 168px; } #div_icon3 { bottom: 30px; left: 70px; } #div_icon4 { bottom: 56px; left: 168px; } .divIconClass { position: relative; width: 25px; height: 25px; } .imgIconClass { width: 1px; height: 1px; left: 70px; }
// 圖片列表 var _imageBase64 = new Array(); // 文字描述的圖片 var _imageText = new String(); // 令牌 var _id; /** * 設(shè)置當(dāng)前圖片 * @param {any} imageText 描述文字的圖片 * @param {any} imageBase64 圖片列表 * @param {any} img_index 圖片的序號(hào) */ function setCurrentImageBase64(imageText, imageBase64, img_index) { // 顯示描述文字 _imageText = 'data:image/webp;base64,' + imageText; document.getElementById('backTextImage').src = _imageText; // 顯示圖片 for (var i = 0; i < imageBase64.length; i++) { _imageBase64[i] = 'data:image/webp;base64,' + imageBase64[i]; document.getElementById('backImage' + (i + 1)).src = _imageBase64[i]; document.getElementById('backImage' + (i + 1)).attributes["val1"] = img_index[i]; } } /** * 驗(yàn)證方法 * @param {any} code 驗(yàn)證碼 */ function check(code) { $.get("Check?code=" + code + "&id=" + _id, function (data) { var obj = JSON.parse(data); if (obj.code == "0") { alert("驗(yàn)證成功"); } else { alert("驗(yàn)證失敗"); } location.reload(); }); } window.onload = function () { $.get("Create", function (data) { // 獲取圖片和令牌 var obj = JSON.parse(data); _id = obj.data.id; // console.log(obj.data.img_index.length); setCurrentImageBase64(obj.data.img_text, obj.data.img, obj.data.img_index); }); // 點(diǎn)擊圖片 $(".img_check").click(function (event) { var id = event.currentTarget.id; var index = id.replace("backImage", ""); // console.log(event.currentTarget.attributes["val1"]); if (event.currentTarget.attributes["checked"].value == "0") { // 選中狀態(tài) event.currentTarget.attributes["checked"].value = "1"; $("#imgIcon" + index).css("height", "25"); $("#imgIcon" + index).css("width", "25"); } else { // 取消選中狀態(tài) event.currentTarget.attributes["checked"].value = "0"; $("#imgIcon" + index).css("height", "1"); $("#imgIcon" + index).css("width", "1"); } }); // 提交按鈕 $("#button_submit").click(function () { var result = ""; var v1 = $("#backImage1"); var v2 = $("#backImage2"); var v3 = $("#backImage3"); var v4 = $("#backImage4"); if (v1[0].attributes["checked"].value == "1") { var code = v1[0].attributes["val1"]; result = result + code + "," } if (v2[0].attributes["checked"].value == "1") { var code = v2[0].attributes["val1"]; result = result + code + "," } if (v3[0].attributes["checked"].value == "1") { var code = v3[0].attributes["val1"]; result = result + code + "," } if (v4[0].attributes["checked"].value == "1") { var code = v4[0].attributes["val1"]; result = result + code + "," } if (result.length <= 0) { alert("請(qǐng)選擇圖片"); return; } else { result = result.substring(0, result.length - 1); } check(result); }) }
效果圖:
到此這篇關(guān)于C#實(shí)現(xiàn)圖像選擇驗(yàn)證碼的示例代碼的文章就介紹到這了,更多相關(guān)C# 圖像選擇驗(yàn)證碼內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#實(shí)現(xiàn)的三種模擬自動(dòng)登錄和提交POST信息的方法
這篇文章主要介紹了C#實(shí)現(xiàn)的三種模擬自動(dòng)登錄和提交POST信息的方法,分別列舉了WebBrowser、WebClient及HttpWebRequest實(shí)現(xiàn)自動(dòng)登錄及提交POST的相關(guān)實(shí)現(xiàn)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-11-11C#實(shí)現(xiàn)txt定位指定行完整實(shí)例
這篇文章主要介紹了C#實(shí)現(xiàn)txt定位指定行的方法,涉及C#針對(duì)文本文件進(jìn)行光標(biāo)定位的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-08-08C# string格式的日期時(shí)間字符串轉(zhuǎn)為DateTime類型的方法
這篇文章主要介紹了C# string格式的日期時(shí)間字符串轉(zhuǎn)為DateTime類型的方法,需要的朋友可以參考下2017-02-02C#基于Linq和反射實(shí)現(xiàn)數(shù)據(jù)持久化框架Xml4DB詳解
在本篇文章里小編給大家整理的是關(guān)于C#基于Linq和反射實(shí)現(xiàn)數(shù)據(jù)持久化框架Xml4DB相關(guān)知識(shí)點(diǎn),有需要的朋友們學(xué)習(xí)下。2019-08-08javascript函數(shù)中執(zhí)行c#函數(shù)的方法
這篇文章主要介紹了javascript和c#函數(shù)和變量互相調(diào)用的方法,大家參考使用吧2014-01-01c#只讀字段和常量的區(qū)別,以及靜態(tài)構(gòu)造函數(shù)的使用實(shí)例
這篇文章主要介紹了c#只讀字段和常量的區(qū)別,以及靜態(tài)構(gòu)造函數(shù)的使用實(shí)例,有需要的朋友可以參考一下2013-12-12解析C#設(shè)計(jì)模式編程中外觀模式Facade Pattern的應(yīng)用
這篇文章主要介紹了C#設(shè)計(jì)模式編程中外觀模式Facade Pattern的應(yīng)用,外觀模式中分為門面(Facade)和子系統(tǒng)(subsystem)兩個(gè)角色來進(jìn)行實(shí)現(xiàn),需要的朋友可以參考下2016-02-02