zoukankan      html  css  js  c++  java
  • 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;
            }

    效果如图:

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

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

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

    项目源码地址:

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

    作者: 刘帅超

    出处: http://www.cnblogs.com/liemei

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出, 原文链接

    如有问题, 可邮件(liushuaichao159@163.com)咨询.

  • 相关阅读:
    js-事件总结
    iquery-个人总结
    CSS3-页面样式
    野生码农狂奔中的2014年度年终总结
    算不算被虚度的这几年
    在Ubuntu 12.4 下安装 nginx, MySQL, PHP
    使用WP8最新的AudioVideoCaptureDevice类制作录像应用
    WP8 MediaElement 实现循环播放
    WPF(WP7、WP8)多个Listbox嵌套时滚动问题的解决
    Weibo SDK WP版本回调参数没有uid的解决方法
  • 原文地址:https://www.cnblogs.com/liemei/p/7060831.html
Copyright © 2011-2022 走看看