C#實(shí)現(xiàn)圖像選擇驗(yàn)證碼的示例代碼
開發(fā)環(huán)境:C#,VS2019,.NET Core 3.1,ASP.NET Core
前幾年使用12306購(gòu)買火車票時(shí)使用過(guò)這種驗(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)
{
// 通過(guò)
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方法用來(lái)將圖片對(duì)象轉(zhuǎn)成Base64字符串
/// <summary>
/// 獲取隨機(jī)的文字和驗(yàn)證碼.
/// </summary>
/// <returns>
/// 第一個(gè)參數(shù) - 圖片的類型(文字描述)
/// 第二個(gè)參數(shù) - 圖片數(shù)組,用來(lái)顯示圖片
/// 第三個(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ù)組,用來(lái)顯示圖片
/// 第二個(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-11
C#實(shí)現(xiàn)txt定位指定行完整實(shí)例
這篇文章主要介紹了C#實(shí)現(xiàn)txt定位指定行的方法,涉及C#針對(duì)文本文件進(jìn)行光標(biāo)定位的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-08-08
C# string格式的日期時(shí)間字符串轉(zhuǎn)為DateTime類型的方法
這篇文章主要介紹了C# string格式的日期時(shí)間字符串轉(zhuǎn)為DateTime類型的方法,需要的朋友可以參考下2017-02-02
C#基于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-08
javascript函數(shù)中執(zhí)行c#函數(shù)的方法
這篇文章主要介紹了javascript和c#函數(shù)和變量互相調(diào)用的方法,大家參考使用吧2014-01-01
c#只讀字段和常量的區(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è)角色來(lái)進(jìn)行實(shí)現(xiàn),需要的朋友可以參考下2016-02-02

