欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Asp.net Web Api实现图片点击式图片验证码功能

程序员文章站 2022-06-14 15:10:10
现在验证码的形式越来越丰富,今天要实现的是在点击图片中的文字来进行校验的验证码,如图 这种验证码验证是验证鼠标是否选中了图片中文字的位置,以及选择的顺序,产生验证码的...

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

Asp.net Web Api实现图片点击式图片验证码功能

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

验证码图片的类

/// <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;
  }

效果如图:

Asp.net Web Api实现图片点击式图片验证码功能

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

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实现图片点击式图片验证码,希望对大家有所帮助