现在验证码的形式越来越丰富,今天要实现的是在点击图片中的文字来进行校验的验证码,如图

这种验证码验证是验证鼠标是否选中了图片中文字的位置,以及选择的顺序,产生验证码的时候可以提供一组底图,然后随机获取一张图片,随机选取几个字,然后把文字的顺序打乱,分别随机放到图片的一个位置上,然后记录文字的位置和顺序,验证的时候验证一下文字的位置和顺序即可

验证码图片的类

    /// <summary>
/// 二维码图片
/// </summary>
public class VerCodePic
{
/// <summary>
/// 图片链接
/// </summary>
public string PicURL { get; set; }
/// <summary>
/// 第一个字位置
/// </summary>
public FontPoint Font1 { get; set; }
/// <summary>
/// 第二个字位置
/// </summary>
public FontPoint Font2 { get; set; }
/// <summary>
/// 第三个字位置
/// </summary>
public FontPoint Font3 { get; set; }
/// <summary>
/// 第四个字位置
/// </summary>
public FontPoint Font4 { get; set; }
}
/// <summary>
/// 文字位置
/// </summary>
public class FontPoint
{
public int X { get; set; }
public int Y { get; set; }
}

生成验证码图片验证码的方法,在这个方法中指定了生成的验证码图片中字体大小为20个像素,因为验证码底图的大小是固定的,所以就把验证码底图按照字体的大小分成了若干个网格位置,指定一个文字在图片中的位置时只需要随机获取其中一个网格即可,如果这个网格中没有指定过文字,那就把文字放到这个网格中。

提前设定网格的方法

  private static ArrayList _FontPoint;
public static ArrayList FontPoint
{
get
{
if (_FontPoint==null)
{
_FontPoint = new ArrayList(); for (int x=;x<;x++)
{
for (int y=;y<;y++)
{
_FontPoint.Add(new Models.FontPoint() { X = x * , Y = y * });
}
}
}
return _FontPoint;
}
}

我选定的验证码底图为280*100的,所以按照上边的方法将图片分成了若干个网格,在下边设定一个文字位置的时候随机选取其中一个位置,而且给每个字都设定了不一样的颜色

 /// <summary>
/// 根据文字和图片获取验证码图片
/// </summary>
/// <param name="content"></param>
/// <param name="picFileName"></param>
/// <returns></returns>
public static VerCodePic GetVerCodePic(string content,string picFileName,int fontSize=)
{
ClassLoger.Info("FileHelper.GetVerCodePic","开始生成二维码");
Bitmap bmp = new Bitmap(picFileName);
List<int> hlist = new List<int>();
VerCodePic codepic = new VerCodePic();
int i = Utils.GetRandom(, SystemSet.FontPoint.Count - );
codepic.Font1 = SystemSet.FontPoint[i] as FontPoint;
hlist.Add(i); A: int i2 = Utils.GetRandom(, SystemSet.FontPoint.Count - );
if (hlist.Contains(i2))
goto A;
codepic.Font2 = SystemSet.FontPoint[i2] as FontPoint;
hlist.Add(i2); B: int i3 = Utils.GetRandom(, SystemSet.FontPoint.Count - );
if (hlist.Contains(i3))
goto B;
hlist.Add(i3);
codepic.Font3 = SystemSet.FontPoint[i3] as FontPoint; C: int i4 = Utils.GetRandom(, SystemSet.FontPoint.Count - );
if (hlist.Contains(i4))
goto C;
hlist.Add(i4);
codepic.Font4 = SystemSet.FontPoint[i4] as FontPoint;string fileName = (content + "-" + picFileName+"-"+i+"|"+i2+"|"+i3+"|"+i4).MD5()+Path.GetExtension(picFileName);
string dir = Path.Combine(SystemSet.ResourcesPath, SystemSet.VerCodePicPath);
string filePath = Path.Combine(dir, fileName);
if (File.Exists(filePath))
{
codepic.PicURL = string.Format("{0}/{1}/{2}", SystemSet.WebResourcesSite, SystemSet.VerCodePicPath, fileName);
return codepic;
}
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
} Graphics g = Graphics.FromImage(bmp);
Font font = new Font("微软雅黑", fontSize, GraphicsUnit.Pixel);
SolidBrush sbrush = new SolidBrush(Color.Black);
SolidBrush sbrush1 = new SolidBrush(Color.Peru);
SolidBrush sbrush2 = new SolidBrush(Color.YellowGreen);
SolidBrush sbrush3 = new SolidBrush(Color.SkyBlue);
List<char> fontlist = content.ToList();
ClassLoger.Info("FileHelper.GetVerCodePic", fontlist.Count.ToString());
g.DrawString(fontlist[].TryToString(), font, sbrush, new PointF(codepic.Font1.X, codepic.Font1.Y));
g.DrawString(fontlist[].TryToString(), font, sbrush1, new PointF(codepic.Font2.X, codepic.Font2.Y));
g.DrawString(fontlist[].TryToString(), font, sbrush2, new PointF(codepic.Font3.X, codepic.Font3.Y));
g.DrawString(fontlist[].TryToString(), font, sbrush3, new PointF(codepic.Font4.X, codepic.Font4.Y)); bmp.Save(filePath, ImageFormat.Jpeg);
codepic.PicURL = string.Format("{0}/{1}/{2}",SystemSet.WebResourcesSite, SystemSet.VerCodePicPath, fileName);
return codepic;
}

获取图片验证码的api接口,在这个接口中从成语库中随机选取了一个成语,然后随机选取了一个图片,然后调用生成图片验证码的方法,生成了图片验证码,并且把验证码对应的信息缓存在redis中,设定缓存时间,将redis的key作为一个临时令牌随同验证码返回

 /// <summary>
/// 获取验证码,有效时间10分钟
/// </summary>
/// <returns></returns>
[HttpGet]
[Route("vercode")]
public JsonResult<VerCodePicViewModel> VerCodePic()
{
JsonResult<VerCodePicViewModel> result = new JsonResult<VerCodePicViewModel>();
result.code = ;
result.msg = "OK";
try
{
ClassLoger.Info("VerCodePic","开始获取成语");
cy_dictBll cybll = new cy_dictBll();
IList<cy_dict> cylist = cybll.GetAllcy_dict();
ClassLoger.Info("VerCodePic", cylist.Count.ToString());
int i = Utils.GetRandom(, cylist.Count-);
ClassLoger.Info("VerCodePic",i.ToString());
cy_dict cy = cylist[i];
ClassLoger.Info("VerCodePic成语:",cy.chengyu);
VerCodePicViewModel vcvm = new VerCodePicViewModel(); string sourcePic = FileHelper.GetVerCodePicResource();
if (sourcePic.IsNull() || !File.Exists(sourcePic))
{
sourcePic = @"E:\WebResources\images\VerCodePicSource\1.jpg";
}
ClassLoger.Info("VerCodePic图片",sourcePic);
VerCodePic codepic = FileHelper.GetVerCodePic(cy.chengyu, sourcePic);
vcvm.content = cy.chengyu;
vcvm.MainPic = codepic.PicURL;
result.Result = vcvm; string key = cookieKey();
RedisBase.Item_Set(key, codepic);
RedisBase.ExpireEntryAt(key,DateTime.Now.AddMinutes());
result.ResultMsg = key;
} catch (Exception ex)
{
ClassLoger.Error("AccountController.VerCodePic",ex);
result.code = -;
result.msg = "AccountController.VerCodePic发生异常:"+ex.Message;
}
return result;
}

效果如图:

图片验证码校验接口参数结构

public class CheckPicCodeViewModel
{
/// <summary>
/// 客户端令牌
/// </summary>
public string token { get; set; } public double x1 { get; set; } public double x2 { get; set; } public double x3 { get; set; } public double x4 { get; set; } public double y1 { get; set; } public double y2 { get; set; } public double y3 { get; set; } public double y4 { get; set; }
}

验证码校验接口

/// <summary>
/// 校验图片验证码是否正确
/// </summary>
/// <param name="piccode"></param>
/// <returns></returns>
[HttpPost]
[Route("checkpiccode")]
public async Task<IHttpActionResult> CheckPicCode([FromBody]CheckPicCodeViewModel piccode)
{
JsonResult<bool> result = new JsonResult<bool>();
result.code = ;
result.msg = "OK";
if (piccode == null)
{
result.Result = false;
result.ResultMsg = "参数错误";
return Ok(result);
}
if (string.IsNullOrEmpty(piccode.token) || !RedisBase.ContainsKey(piccode.token))
{
result.Result = false;
result.ResultMsg = "验证码已过期";
return Ok(result);
}
result.Result = await Task.Run<bool>(() => {
bool flag = false;
VerCodePic codepic = RedisBase.Item_Get<VerCodePic>(piccode.token);
if (Math.Abs(codepic.Font1.X - piccode.x1) > 0.5 || Math.Abs(codepic.Font1.Y - piccode.y1) > 0.5
|| Math.Abs(codepic.Font2.X - piccode.x2) > 0.5 || Math.Abs(codepic.Font2.Y - piccode.y2) > 0.5
|| Math.Abs(codepic.Font3.X - piccode.x3) > 0.5 || Math.Abs(codepic.Font3.Y - piccode.y3) > 0.5
|| Math.Abs(codepic.Font4.X - piccode.x4) > 0.5 || Math.Abs(codepic.Font4.Y - piccode.y4) > 0.5)
{
flag = false;
result.ResultMsg = "验证码错误";
}
else
{
flag = true;
result.ResultMsg = "验证码正确";
}
return flag;
});
return Ok(result);
}

传入用户选中的位置和顺序,并对其进行验证

项目源码地址:

https://github.com/liemei/asp.netOpenService.git

asp.net web api实现图片点击式图片验证码的更多相关文章

  1. 对一个前端使用AngularJS后端使用ASP.NET Web API项目的理解(4)

    chsakell分享了一个前端使用AngularJS,后端使用ASP.NET Web API的项目. 源码: https://github.com/chsakell/spa-webapi-angula ...

  2. C#版ASP.NET Web API使用示例

    为更好更快速的上手Webapi设计模式的接口开发,本文详细解释了在Web API接口的开发过程中,我们可能会碰到各种各样的问题总结了这篇,希望对大家有所帮助. 1:在接口定义中确定MVC的get或者P ...

  3. 在一个空ASP.NET Web项目上创建一个ASP.NET Web API 2.0应用

    由于ASP.NET Web API具有与ASP.NET MVC类似的编程方式,再加上目前市面上专门介绍ASP.NET Web API 的书籍少之又少(我们看到的相关内容往往是某本介绍ASP.NET M ...

  4. ASP.NET Core 中文文档 第二章 指南 (09) 使用 Swagger 生成 ASP.NET Web API 在线帮助测试文档

    原文:ASP.NET Web API Help Pages using Swagger 作者:Shayne Boyer 翻译:谢炀(kiler) 翻译:许登洋(Seay) 对于开发人员来说,构建一个消 ...

  5. asp.net web api 的版本升级到 2.2的记录

    asp.net web api 的版本 升级到 2.2的记录 asp.net web api 2.2相比1.0提升了不少 而且其中最重要的就是有了在线文档的自动字段注释的功能 再也不用写详细的字段说明 ...

  6. 使用ASP.NET Web API Help Pages 创建在线接口文档

    操作步骤 1.新建Web API项目 2.在项目Areas文件夹下找到以下文件,取消注释图中代码. 3.右键解决方案,属性,如图设置. 4.运行程序,点击右上角API 接口列表: 详情-无参数: 详情 ...

  7. 初试ASP.NET Web API/MVC API(附Demo)

    写在前面 HTTP RESTful 创建Web API 调用Web API 运行截图及Demo下载 ASP.NET Web API是​​一个框架,可以很容易构建达成了广泛的HTTP服务客户端,包括浏览 ...

  8. ASP.NET Web API 2 入门

    本文参考:http://www.asp.net/web-api/overview/getting-started-with-aspnet-web-api/tutorial-your-first-web ...

  9. 旅图beta版 asp.net web api 单元测试

    旅图 beta版 asp.net web api 单元测试 测试接口:http://120.27.7.115:1010/Help 测试目的 对每个接口单元进行测试,保证每个接口的可靠性. 单元描述 注 ...

随机推荐

  1. css定位 浮动 伪类 margin

    一,margin .标准文档流,margin在竖直方向的不叠加,以较大的为准 .使用margin: auto;的盒子必须有明确的width,并且只有标准文档流的盒子 才能使用margin: auto; ...

  2. 「七天自制PHP框架」第三天:PHP实现的设计模式

    往期回顾:「七天自制PHP框架」第二天:模型与数据库,点击此处 原文地址:http://www.cnblogs.com/sweng/p/6624845.html,欢迎关注:编程老头 为什么要使用设计模 ...

  3. WebSocket学习总结

    一 .websocket 已解决      但是websocket延伸出来的网络编程还有好多知识点没有清理.主要的流程和实现方式已经大概了解清楚,下面从学习的进度思路来一点点复习.        网络 ...

  4. SpringData系列一 Spring Data的环境搭建

    本节作为主要讲解Spring Data的环境搭建 JPA Spring Data :致力于减少数据访问层(DAO)的开发量.开发者唯一要做的就是声明持久层的接口,其他都交给Spring Data JP ...

  5. Node.js~ioredis处理耗时请求时连接数瀑增

    回到目录 关于redis连接数过高的解释 对于node.js开发环境里,使用传统的redis或者使用ioredis都是不错的选择,而在处理大数据请求程中,偶尔出现了连接池( redis服务端的最大可用 ...

  6. 【JAVAWEB学习笔记】02_HTML&CSS

    //--------------纯文本版------------------------------------------------- 今日新增单词(更多属性查看手册) form:表单 (要提交的 ...

  7. C#中string,char[],byte[]互相转换

    string 转换成 Char[] string ss = "我爱你,中国"; char[] cc = ss.ToCharArray(); Char[] 转换成string str ...

  8. conda 使用清华大学开源软件镜像

    conda 使用清华大学开源软件镜像 Anaconda的安装步骤不在本文的讨论中,我们主要是学习一下如何配置conda的镜像,以及一些问题的解决过程 配置镜像 在conda安装好之后,默认的镜像是官方 ...

  9. 字符串时间和NSDate相互转换的坑

    项目中服务器传回来的时间是这种格式的 Sep 5, 2016 6:59:05 PM 现在要将这段字符串转换成 2016-09-05 06:59 被坑的地方有2个点 服务器传回来的英文的Sep,调试的时 ...

  10. (HTTPS)-https原理及tomcat配置https方法

    一. 什么是HTTPS 在说HTTPS之前先说说什么是HTTP,HTTP就是我们平时浏览网页时候使用的一种协议.HTTP协议传 输的数据都是未加密的,也就是明文的,因此使用HTTP协议传输隐私信息非常 ...