Asp.net Web Api实现图片点击式图片验证码功能
程序员文章站
2023-11-09 12:28:10
现在验证码的形式越来越丰富,今天要实现的是在点击图片中的文字来进行校验的验证码,如图
这种验证码验证是验证鼠标是否选中了图片中文字的位置,以及选择的顺序,产生验证码的...
现在验证码的形式越来越丰富,今天要实现的是在点击图片中的文字来进行校验的验证码,如图
这种验证码验证是验证鼠标是否选中了图片中文字的位置,以及选择的顺序,产生验证码的时候可以提供一组底图,然后随机获取一张图片,随机选取几个字,然后把文字的顺序打乱,分别随机放到图片的一个位置上,然后记录文字的位置和顺序,验证的时候验证一下文字的位置和顺序即可
验证码图片的类
/// <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=0;x<10;x++) { for (int y=0;y<5;y++) { _fontpoint.add(new models.fontpoint() { x = x * 28, y = y * 20 }); } } } 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=20) { classloger.info("filehelper.getvercodepic","开始生成二维码"); bitmap bmp = new bitmap(picfilename); list<int> hlist = new list<int>(); vercodepic codepic = new vercodepic(); int i = utils.getrandom(0, systemset.fontpoint.count - 1); codepic.font1 = systemset.fontpoint[i] as fontpoint; hlist.add(i); a: int i2 = utils.getrandom(0, systemset.fontpoint.count - 1); if (hlist.contains(i2)) goto a; codepic.font2 = systemset.fontpoint[i2] as fontpoint; hlist.add(i2); b: int i3 = utils.getrandom(0, systemset.fontpoint.count - 1); if (hlist.contains(i3)) goto b; hlist.add(i3); codepic.font3 = systemset.fontpoint[i3] as fontpoint; c: int i4 = utils.getrandom(0, systemset.fontpoint.count - 1); 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[0].trytostring(), font, sbrush, new pointf(codepic.font1.x, codepic.font1.y)); g.drawstring(fontlist[1].trytostring(), font, sbrush1, new pointf(codepic.font2.x, codepic.font2.y)); g.drawstring(fontlist[2].trytostring(), font, sbrush2, new pointf(codepic.font3.x, codepic.font3.y)); g.drawstring(fontlist[3].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 = 1; 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(0, cylist.count-1); 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(10)); result.resultmsg = key; } catch (exception ex) { classloger.error("accountcontroller.vercodepic",ex); result.code = -1; 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 = 1; 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); }
传入用户选中的位置和顺序,并对其进行验证。
以上所述是小编给大家介绍的asp.net web api实现图片点击式图片验证码,希望对大家有所帮助