侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

写一个含数字,拼音,汉字的验证码生成类

技术  /  管理员 发布于 7年前   329

本次和大家分享的是一个集成1:小写拼音 2:大写拼音 3:数字 4:汉字的验证码生成类,从标题来看感觉很普通的样子,没错的确很普通,只是这个验证码类生成的时候可以通过参数指定验证码返回格式的规则,更主要的是希望能给大家带来一定的实用性,本章例子也会有一个mvc使用验证码校验的场景,希望大家能够喜欢。

» 验证码生成流程图

» 验证码生成池代码的解析

» 把验证代码画到图片上

» mvc登录操作测试验证码正确性

下面一步一个脚印的来分享:

» 验证码生成流程图

首先,咋们来看一下本次分享的验证码生成类的生成流程图:

能看到此图描述的编码生成池对应的是几个不同的编码内容,这里主要根据参数设置允许同时获取不同编码内容,从而到达文字,拼音,汉字组合而成验证码,具体规则设置由参数而定;

» 验证码生成池代码的解析

首先,由上面流程图分析的内容能看出,这个验证码生成池子需要并行获取不同类型验证码数据,才能满足组合的验证码,因此有了下面的代码:

/// <summary> /// 创建验证码 /// </summary> /// <param name="codeType">1:小写拼音 2:大写拼音 3:数字 4:汉字</param> /// <returns></returns> public static string CreateCode(string codeType = "1|2|3|4") { var code = string.Empty; try { if (string.IsNullOrWhiteSpace(codeType) || codeType.IndexOf('|') < 0) { codeType = "1|2|3|4"; } var codeTypeArr = codeType.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries); var strLen = codeTypeArr.Length; //任务 Task<string>[] taskArr = new Task<string>[strLen]; for (int i = 0; i < strLen; i++) {  var val = codeTypeArr[i];  switch (val)  {  case "1": //小写拼音  taskArr[i] = Task.Factory.StartNew<string>(() => { return GetPinYinOrUpper(false); });  break;  case "2": //大写拼音  taskArr[i] = Task.Factory.StartNew<string>(() => { return GetPinYinOrUpper(); });  break;  case "3": //数字  taskArr[i] = Task.Factory.StartNew<string>(() => { return GetShuZi(); });  break;  case "4": //汉字  taskArr[i] = Task.Factory.StartNew<string>(() => { return GetHanZi(); });  break;  default:  break;  } } //等待完成 30s Task.WaitAll(taskArr, TimeSpan.FromSeconds(30)); foreach (var item in taskArr) {  code += item.Result; } } catch (Exception ex) { code = "我爱祖国"; } return code; }

这里继续使用了关键字Task,来分发任务获取不同的验证码内容,个人认为最主要的还是通过参数设置 string codeType = "1|2|3|4" ,来确定验证码的组合方式,这样也达到了验证码格式的多样性;

» 把验证代码画到图片上

首先,咋们要明确的是要吧文字画在某个图片上,那么需要用到Graphics关键字,以此来创建画布把咋们的验证编码画到图片上,这里先上代码:

/// <summary> /// 生成验证码图片流 /// </summary> /// <param name="code">验证码文字</param> /// <returns>流</returns> public static byte[] CreateValidateCodeStream(string code = "我爱祖国", int fontSize = 18, int width = 0, int height = 0, string fontFamily = "华文楷体") { var bb = new byte[0]; //初始化画布 var padding = 2; var len = code.Length; width = width <= 0 ? fontSize * 2 * (len - 1) + padding * 4 : width; height = height <= 0 ? fontSize * 2 : height; var image = new Bitmap(width, height); var g = Graphics.FromImage(image); try { var random = new Random(); //清空背景色 g.Clear(Color.White); //画横向中间干扰线 var x1 = 0; var y1 = height / 2; var x2 = width; var y2 = y1; g.DrawLine(new Pen(Color.DarkRed), x1, y1, x2, y2); //字体 var font = new Font(fontFamily, fontSize, (FontStyle.Bold | FontStyle.Italic)); var brush = new LinearGradientBrush(new Rectangle(0, 0, image.Width, image.Height),  Color.Blue, Color.DarkRed, 1f, true); //画文字 var stringFomart = new StringFormat(); //垂直居中 stringFomart.LineAlignment = StringAlignment.Center; //水平居中 stringFomart.Alignment = StringAlignment.Center; var rf = new Rectangle(Point.Empty, new Size(width, height)); g.DrawString(code, font, brush, rf, stringFomart); //画图片的前景干扰点 for (int i = 0; i < 100; i++) {  var x = random.Next(image.Width);  var y = random.Next(image.Height);  image.SetPixel(x, y, Color.FromArgb(random.Next())); } //画图片的边框线 g.DrawRectangle(new Pen(Color.Silver), 0, 0, image.Width - 1, image.Height - 1); //保存图片流 var stream = new MemoryStream(); image.Save(stream, ImageFormat.Jpeg); //输出图片流 bb = stream.ToArray(); } catch (Exception ex) { } finally { g.Dispose(); image.Dispose(); } return bb; }

这个列出画验证码图片方法的关键点:

1. 图片的高和宽度需要设置,这个根据不同页面布局方式而定,所以这里吧高和宽用作参数传递

2. 干扰线:通常验证码图片都以一两条干扰线,主要防止某些恶意用户使用图片识别软件进行不正规破解请求,我这里干扰线只设置了横向居中的一天直线代码如: g.DrawLine(new Pen(Color.DarkRed), x1, y1, x2, y2);

3. 字体:一个好看的字体通常也一种用户体验,因此这里根据需要参数传递字体;

4. 验证代码位于图片纵横向居中,这里的关键代码是:

 var stringFomart = new StringFormat(); //垂直居中 stringFomart.LineAlignment = StringAlignment.Center; //水平居中 stringFomart.Alignment = StringAlignment.Center;

5.   g.DrawString(code, font, brush, rf, stringFomart); 主要用来把文字画到图片上,这是最关键的地方

6. 咋们通常都是吧验证码弄成图片流,而不是真的生成一个实体的验证码图片保存到服务器上,不然这样服务器很快就会磁盘不足,所以

 //保存图片流 var stream = new MemoryStream(); image.Save(stream, ImageFormat.Jpeg); //输出图片流 bb = stream.ToArray();

这句的重要性也不可忽视,主要就把画的内容保存到流中方便使用

7. 最后千万不用忘了使用Dispose释放画布

» mvc登录操作测试验证码正确性

有了上面验证码生成类生成好的验证码图片,那么我们还需要测试验证下正确性和效果;下面我们使用mvc架构来做测试,先创建一个验证码测试Action并生成对应试图ValidCode.cshtml文件,然后自定义几个不同格式的验证码获取Action,代码如下:

public FileResult GetValidateCode() { //返回的验证码文字 var code = string.Empty; var bb_code = ValidateCode.GetValidateCodeStream(ref code); return File(bb_code, "image/jpeg"); } public FileResult GetValidateCode01() { var code = string.Empty; var bb_code = ValidateCode.GetValidateCodeStream(ref code, "1|2|3|4"); return File(bb_code, "image/jpeg"); } public FileResult GetValidateCode02() { var code = string.Empty; var bb_code = ValidateCode.GetValidateCodeStream(ref code, "4|3|2|1"); return File(bb_code, "image/jpeg"); } public FileResult GetValidateCode03() { var code = string.Empty; var bb_code = ValidateCode.GetValidateCodeStream(ref code, "2|2|2|2"); return File(bb_code, "image/jpeg"); } public FileResult GetValidateCode04() { var code = string.Empty; var bb_code = ValidateCode.GetValidateCodeStream(ref code, "4|4|4|4"); return File(bb_code, "image/jpeg"); } public FileResult GetValidateCode05() { var code = string.Empty; var bb_code = ValidateCode.GetValidateCodeStream(ref code, "1|1|1|1"); return File(bb_code, "image/jpeg"); }

感觉上几乎一模一样,只是对应的参数不一样,这里遵循的方法GetValidateCodeStream参数codeType格式是:为空表示自由组合  1:小写拼音 2:大写拼音 3:数字 4:汉字;然后我们往试图中填写如下代码:

<h2>神牛 - 验证码实例</h2><div class="container " id="appVue"> <table class="table table-bordered text-left"> <tbody> <tr> <td>全部随机</td> <td>  <img src="https:home/GetValidateCode" data-src="https:home/GetValidateCode" id="imgCode" />  <input type="text" name="code" placeholder="请输入验证码" class="form-control" />  <button class="btn btn-default">登 录</button>  <span id="msg" style="color:red"></span> </td> </tr> <tr> <td>小写|大写|数字|汉字</td> <td><img src="https:home/GetValidateCode01" data-src="https:home/GetValidateCode01" /></td> </tr> <tr> <td>汉字|数字|大写|小写</td> <td><img src="https:home/GetValidateCode02" data-src="https:home/GetValidateCode02" /></td> </tr> <tr> <td>全部大写</td> <td><img src="https:home/GetValidateCode03" data-src="https:home/GetValidateCode03" /></td> </tr> <tr> <td>全部汉字</td> <td><img src="https:home/GetValidateCode04" data-src="https:home/GetValidateCode04" /></td> </tr> <tr> <td>全部小写</td> <td><img src="https:home/GetValidateCode05" data-src="https:home/GetValidateCode05" /></td> </tr> </tbody> </table></div>

好了咋们生成下项目,看下效果图如下:

能从图中看到我们验证码格式的不同之处,这也是文章开头说的验证码格式的多样性,当然可能还有其他组成格式请允许我暂时忽略,下面我们来做一个点击图片获取新验证码的功能和点击登录按钮去后台程序判断验证码是否匹配的例子,先来修改试图界面代码如下:

@{ ViewBag.Title = "ValidtCode";}<h2>神牛 - 验证码实例</h2><div class="container " id="appVue"> <table class="table table-bordered text-left"> <tbody> <tr> <td>全部随机</td> <td>  <img src="https:home/GetValidateCode" data-src="https:home/GetValidateCode" id="imgCode" />  <input type="text" name="code" placeholder="请输入验证码" class="form-control" />  <button class="btn btn-default">登 录</button>  <span id="msg" style="color:red"></span> </td> </tr> <tr> <td>小写|大写|数字|汉字</td> <td><img src="https:home/GetValidateCode01" data-src="https:home/GetValidateCode01" /></td> </tr> <tr> <td>汉字|数字|大写|小写</td> <td><img src="https:home/GetValidateCode02" data-src="https:home/GetValidateCode02" /></td> </tr> <tr> <td>全部大写</td> <td><img src="https:home/GetValidateCode03" data-src="https:home/GetValidateCode03" /></td> </tr> <tr> <td>全部汉字</td> <td><img src="https:home/GetValidateCode04" data-src="https:home/GetValidateCode04" /></td> </tr> <tr> <td>全部小写</td> <td><img src="https:home/GetValidateCode05" data-src="https:home/GetValidateCode05" /></td> </tr> </tbody> </table></div><script src="https:/article/~/Scripts/jquery-1.10.2.min.js"></script><script type="text/javascript"> $(function () { $("img").on("click", function () { var nowTime = new Date().getTime(); var src = $(this).attr("data-src") + "?t=" + nowTime; if (src.length <= 0) { return; } $(this).attr("src", src); }); $("button").on("click", function () { var msg = $("#msg"); var code = $("input[name='code']").val(); if (code.length <= 0) { msg.html("请输入验证码!"); return; } $.post("/home/UserLogin", { code: code }, function (result) { if (result) {  msg.html(result.Msg);  if (!result.IsOk) {  $("#imgCode").click();  } } }); }) })</script>

然后在Controller中增加如下登录验证代码:

public JsonResult UserLogin(string code) { var data = new Stage.Com.Extend.StageModel.MoData(); if (string.IsNullOrWhiteSpace(code)) { data.Msg = "验证码不能为空"; return Json(data); } var compareCode = Session["code"]; if (!compareCode.Equals(code)) { data.Msg = "验证码错误"; return Json(data); } data.IsOk = true; data.Msg = "验证码验证成功"; return Json(data); } public FileResult GetValidateCode() { //返回的验证码文字 var code = string.Empty; var bb_code = ValidateCode.GetValidateCodeStream(ref code); var key = "code"; if (Session[key] != null) { Session.Remove(key); } Session[key] = code; return File(bb_code, "image/jpeg"); }

由于我这里无法截动态图,所点击测试获取验证码我这里直接给出线上的一个例子,各位可以试试:http://lovexins.com:1001/home/ValidCode,点击获取新验证码的关键代码是:  $(this).attr("src", src); 重新给img元素的scr赋值,不过这里要注意由于浏览器缓存的原因,这里赋值的时候需要加上一个动态参数,我这里是使用时间作为请求参数,因此有了以下的代码: $(this).attr("data-src") + "?t=" + nowTime; 这是特别的地方需要注意;好了咋们来直接测试登陆是否能从后端判断验证码是否正确匹配吧,这里用的是session来保存获取验证码图片返回的验证代码,然后在登陆时候判断用户数据的验证码是否和后台session的验证一样:

验证失败:

验证成功:

好了测试用例就这么多,如果您觉得我这个验证码生成例子还可以并且您希望使用那么请注意,参数的传递,不同得到的验证码格式不同,主要方法是:

/// <summary> /// 获取验证码图片流 /// </summary> /// <param name="codeLen">验证码个数(codeType设置 > codeLen设置)</param> /// <param name="codeType">为空表示自由组合 1:小写拼音 2:大写拼音 3:数字 4:汉字</param> /// <returns></returns> public static byte[] GetValidateCodeStream(ref string code, string codeType = "", int codeLen = 0, int fontSize = 18, int width = 120, int height = 30) { //为空自由组合 if (string.IsNullOrWhiteSpace(codeType)) { for (int i = 0; i < codeLen; i++) {  codeType += rm.Next(1, 5) + "|"; } } code = CreateCode(codeType); return CreateValidateCodeStream(code, fontSize, width: width, height: height); }

具体参数各位可以看下备注,我这里顺便打包下代码,方便分享和使用:验证码生成示例

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持!


  • 上一条:
    利用Typings为Visual Studio Code实现智能提示功能
    下一条:
    五步掌握OOM框架AutoMapper基本使用
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 2024.07.09日OpenAI将终止对中国等国家和地区API服务(0个评论)
    • 2024/6/9最新免费公益节点SSR/V2ray/Shadowrocket/Clash节点分享|科学上网|免费梯子(0个评论)
    • 国外服务器实现api.openai.com反代nginx配置(0个评论)
    • 2024/4/28最新免费公益节点SSR/V2ray/Shadowrocket/Clash节点分享|科学上网|免费梯子(0个评论)
    • 近期文章
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • PHP 8.4 Alpha 1现已发布!(0个评论)
    • Laravel 11.15版本发布 - Eloquent Builder中添加的泛型(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2017-07
    • 2017-08
    • 2017-09
    • 2018-01
    • 2018-07
    • 2018-08
    • 2018-09
    • 2018-12
    • 2019-01
    • 2019-02
    • 2019-03
    • 2019-04
    • 2019-05
    • 2019-06
    • 2019-07
    • 2019-08
    • 2019-09
    • 2019-10
    • 2019-11
    • 2019-12
    • 2020-01
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2020-07
    • 2020-08
    • 2020-09
    • 2020-10
    • 2020-11
    • 2021-04
    • 2021-05
    • 2021-06
    • 2021-07
    • 2021-08
    • 2021-09
    • 2021-10
    • 2021-12
    • 2022-01
    • 2022-02
    • 2022-03
    • 2022-04
    • 2022-05
    • 2022-06
    • 2022-07
    • 2022-08
    • 2022-09
    • 2022-10
    • 2022-11
    • 2022-12
    • 2023-01
    • 2023-02
    • 2023-03
    • 2023-04
    • 2023-05
    • 2023-06
    • 2023-07
    • 2023-08
    • 2023-09
    • 2023-10
    • 2023-12
    • 2024-02
    • 2024-04
    • 2024-05
    • 2024-06
    • 2025-02
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客