C#教程

关注公众号 jb51net

关闭
首页 > 软件编程 > C#教程 > C# 图像选择验证码

C#实现图像选择验证码的示例代码

作者:绿龙术士

为了防止网站被非法登陆,网站一般通过验证码的方式,防止黑客用软件非法登陆,本文主要介绍了C#实现图像选择验证码的示例代码,具有一定的参考价值,感兴趣的可以了解一下

开发环境:C#,VS2019,.NET Core 3.1,ASP.NET Core

前几年使用12306购买火车票时使用过这种验证码,根据文字描述选择对应的图片,文字是随机的,图片也是随机的。

1、建立一个验证码控制器

新建两个方法Create和Check,Create用于创建验证码,Check用于验证它是否有效。

声明一个静态类变量存放列表,列表中存放包含令牌和验证码的对象。

        /// <summary>
        /// 返回多张图片,一个文字和令牌.
        /// </summary>
        /// <returns></returns>
        public string Create()
        {
            try
            {
                VCodeImageSelectModel model = new VCodeImageSelectModel();
                model.id = Guid.NewGuid().ToString();    // 生成令牌
                var vcode = VCodeImageSelectModel.GetVCode();    // 生成验证码
                model.code.text = vcode.Item1;
                model.code.image = vcode.Item4;
                _list.Add(model);
                // 返回结果
                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 = "系统异常";
                var json = JsonConvert.SerializeObject(result);
                return json;
            }
        }
        /// <summary>
        /// 检查验证码是否有效
        /// </summary>
        /// <param name="id">令牌.</param>
        /// <param name="code">验证码.</param>
        /// <returns></returns>
        [HttpGet]
        public string Check(string id, string code)
        {
            try
            {
                ReceiveObject result = new ReceiveObject();
                var list_result = code.Split(',').ToList();    // 拆分验证码为数组
                var list_temp = new List<string>(); 
                if(_list.Find(m => m.id == id) == null)
                {
                    result.code = "999999";
                    result.msg = "系统异常";
                    var json = JsonConvert.SerializeObject(result);
                    return json;
                }
                _list.Find(m => m.id == id).code.image.ForEach(m =>
                {
                    // 复制数组,避免重复提交后仍然能获取到完整的数据
                    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)
                        {
                            // 选中了错误的
                            return false;
                        }
                        else
                        {
                            // 每次将选中的项删除,这样最终得到的数组应该是空的
                            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 = "验证成功";
                    var json = JsonConvert.SerializeObject(result);
                    return json;
                }
                else
                {
                    result.code = "1";
                    result.msg = "验证失败";
                    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 = "系统异常";
                var json = JsonConvert.SerializeObject(result);
                return json;
            }
        }

2、建立一个验证码模型

验证码模型类包括:令牌和验证码属性。

再创建一个类存放GetVCode方法返回的对象包括:图片的类型(它又叫文字描述)的图片,图片数组,图片对应的序号,该类型的图片对应的序号。

DrawImage方法生成图片的类型(它又叫文字描述)的图片

GetVCodeList方法生成图片数组,图片对应的序号,该类型的图片对应的序号。

BitmapToBase64Str方法用来将图片对象转成Base64字符串

        /// <summary>
        /// 获取随机的文字和验证码.
        /// </summary>
        /// <returns>
        ///  第一个参数 - 图片的类型(文字描述)
        ///  第二个参数 - 图片数组,用来显示图片
        ///  第三个参数 - 图片对应的序号
        ///  第四个参数 - 该类型的图片对应的序号
        /// </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>
        /// 获取随机的验证码.
        /// </summary>
        /// <param name="type">图片的类型.</param>
        /// <returns>
        ///  第一个参数 - 图片数组,用来显示图片
        ///  第二个参数 - 图片对应的序号
        ///  第三个参数 - 该类型的图片对应的序号
        /// </returns>
        private static Tuple<List<Bitmap>, List<string>, List<string>> GetVCodeList(string type)
        {
            // 这里的随机码是一个有四个元素的数组,如果发现没有生成指定类型的,就重新生成.
            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;
                    }
                }
                // 判断是否至少生成了一个指定类型的图片
                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
                {
                    // 至少生成了一个指定类型的图片
                    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>
        /// 将图片对象转成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>
        /// 将图片对象转成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>
        /// 绘制验证码的图片.
        /// </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),    // 蓝色(亮)
                Color.FromArgb(25, 25, 112),    // 蓝色(暗)
                Color.FromArgb(192, 192, 192),    // 灰白(亮)
                Color.FromArgb(128, 128, 105),    // 灰白(暗)
            };
            Random random = new Random();
            // 创建画板
            Bitmap bitmap = new Bitmap(85, 50);
            // 创建画笔
            Graphics grp = Graphics.FromImage(bitmap);
            grp.Clear(Color.White);    // 设置背景色为白色
            // 绘制噪点
            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);
            }
            // 绘制随机的线条
            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))
            );
            // 绘制验证码
            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));
            }
            // 在验证码上绘制噪点
            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);
            }
            // 绘制随机的线条
            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、新建一个视图文件

引入jquery,css文件,js方法中添加几个事件 - 点击图片,提交按钮。页面首次加载时调用控制器的Create方法获取图片和令牌。

<link href="~/css/image_select.css" rel="external nofollow"  rel="stylesheet" />
<!-- 展示验证码 -->
<div class="container">
    <div class="main">
        <div>
            请选择所有的<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;
/**
 * 设置当前图片
 * @param {any} imageText 描述文字的图片
 * @param {any} imageBase64 图片列表
 * @param {any} img_index 图片的序号
 */
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];
    }
}
/**
 * 验证方法
 * @param {any} code 验证码
 */
function check(code)
{
    $.get("Check?code=" + code + "&id=" + _id, function (data) {
        var obj = JSON.parse(data);
        if (obj.code == "0") {
            alert("验证成功");
        }
        else {
            alert("验证失败");
        }
        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);
    });
    // 点击图片
    $(".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")
        {
            // 选中状态
            event.currentTarget.attributes["checked"].value = "1";
            $("#imgIcon" + index).css("height", "25");
            $("#imgIcon" + index).css("width", "25");
        }
        else
        {
            // 取消选中状态
            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("请选择图片");
            return;
        }
        else {
            result = result.substring(0, result.length - 1);
        }
        check(result);
    })
}

效果图:

到此这篇关于C#实现图像选择验证码的示例代码的文章就介绍到这了,更多相关C# 图像选择验证码内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家! 

您可能感兴趣的文章:
阅读全文