首页 > 其他分享 >图形验证码+短信验证码实战

图形验证码+短信验证码实战

时间:2023-08-09 16:11:44浏览次数:39  
标签:实战 rand 短信 int 验证码 Next var new

前言:

  上一篇分分享了基于阿里云实现的短信验证码文章,考虑到为了防止登录时,非人工操作,频繁获取验证码,趁热打铁,现在添加了图片验证码服务功能。借鉴网上传统的做法,把实现这两个验证的功能做成有个独立的服务,通过Http分别请求获取校验图片验证码和短信验证码。

一、需求描述:

  • 图形验证码为,短信验证码为6位纯数字
  • 同一系统图片验证码缓存中只存在一个,没有有效期,每次刷新更新旧图形验证码
  • 短信验证码有效期2分钟
  • 每个手机号60秒内只能发送一次短信验证码,在服务器端执行校验
  • 同一个手机号在同一时间内可以有多个有效的短信验证码,根据不同系统类型区分
  • 每个短信验证码至多可被使用3次,无论和请求中的验证码是否匹配,随后立即作废,以防止暴力攻击
  • 发送短信验证码之前,先验证图形验证码是否正确

二、图片验证码实现:

生成随机验证码字符串:

 /// <summary>
        /// 获取随机验证码
        /// </summary>
        /// <returns></returns>
        public static string GenerateCaptchaCode()
        {
            Random rand = new Random();
            int maxRand = Letters.Length - 1;

            StringBuilder sb = new StringBuilder();

            for (int i = 0; i < 4; i++)
            {
                int index = rand.Next(maxRand);
                sb.Append(Letters[index]);
            }

            return sb.ToString();
        }

随机验证码生成验证码图片:

 /// <summary>
        /// 生成随机验证码图片
        /// </summary>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <param name="captchaCode"></param>
        /// <returns></returns>
        public static CaptchaResult GenerateCaptcha(int width, int height, string captchaCode)
        {
            using (Bitmap baseMap = new Bitmap(width, height))
            using (Graphics graph = Graphics.FromImage(baseMap))
            {
                Random rand = new Random();

                graph.Clear(GetRandomLightColor());

                DrawCaptchaCode();
                DrawDisorderLine();
                AdjustRippleEffect();

                MemoryStream ms = new MemoryStream();

                baseMap.Save(ms, ImageFormat.Png);

                return new CaptchaResult { CaptchaCode = captchaCode, CaptchaByteData = ms.ToArray(), Timestamp = DateTime.Now };

                int GetFontSize(int imageWidth, int captchCodeCount)
                {
                    var averageSize = imageWidth / captchCodeCount;

                    return Convert.ToInt32(averageSize);
                }

                Color GetRandomDeepColor()
                {
                    int redlow = 160, greenLow = 100, blueLow = 160;
                    return Color.FromArgb(rand.Next(redlow), rand.Next(greenLow), rand.Next(blueLow));
                }

                Color GetRandomLightColor()
                {
                    int low = 180, high = 255;

                    int nRend = rand.Next(high) % (high - low) + low;
                    int nGreen = rand.Next(high) % (high - low) + low;
                    int nBlue = rand.Next(high) % (high - low) + low;

                    return Color.FromArgb(nRend, nGreen, nBlue);
                }

                void DrawCaptchaCode()
                {
                    SolidBrush fontBrush = new SolidBrush(Color.Black);
                    int fontSize = GetFontSize(width, captchaCode.Length);
                    Font font = new Font(FontFamily.GenericSerif, fontSize, FontStyle.Bold, GraphicsUnit.Pixel);
                    for (int i = 0; i < captchaCode.Length; i++)
                    {
                        fontBrush.Color = GetRandomDeepColor();

                        int shiftPx = fontSize / 6;

                        //float x = i * fontSize + rand.Next(-shiftPx, shiftPx) + rand.Next(-shiftPx, shiftPx);
                        float x = i * fontSize + rand.Next(-shiftPx, shiftPx) / 2;
                        //int maxY = height - fontSize;
                        int maxY = height - fontSize * 2;
                        if (maxY < 0)
                        {
                            maxY = 0;
                        }
                        float y = rand.Next(0, maxY);

                        graph.DrawString(captchaCode[i].ToString(), font, fontBrush, x, y);
                    }
                }

                void DrawDisorderLine()
                {
                    Pen linePen = new Pen(new SolidBrush(Color.Black), 2);
                    //for (int i = 0; i < rand.Next(3, 5); i++)
                    for (int i = 0; i < 2; i++)
                    {
                        linePen.Color = GetRandomDeepColor();

                        Point startPoint = new Point(rand.Next(0, width), rand.Next(0, height));
                        Point endPoint = new Point(rand.Next(0, width), rand.Next(0, height));
                        graph.DrawLine(linePen, startPoint, endPoint);

                        //Point bezierPoint1 = new Point(rand.Next(0, width), rand.Next(0, height));
                        //Point bezierPoint2 = new Point(rand.Next(0, width), rand.Next(0, height));

                        //graph.DrawBezier(linePen, startPoint, bezierPoint1, bezierPoint2, endPoint);
                    }
                }

                void AdjustRippleEffect()
                {
                    short nWave = 6;
                    int nWidth = baseMap.Width;
                    int nHeight = baseMap.Height;

                    Point[,] pt = new Point[nWidth, nHeight];

                    for (int x = 0; x < nWidth; ++x)
                    {
                        for (int y = 0; y < nHeight; ++y)
                        {
                            var xo = nWave * Math.Sin(2.0 * 3.1415 * y / 128.0);
                            var yo = nWave * Math.Cos(2.0 * 3.1415 * x / 128.0);

                            var newX = x + xo;
                            var newY = y + yo;

                            if (newX > 0 && newX < nWidth)
                            {
                                pt[x, y].X = (int)newX;
                            }
                            else
                            {
                                pt[x, y].X = 0;
                            }


                            if (newY > 0 && newY < nHeight)
                            {
                                pt[x, y].Y = (int)newY;
                            }
                            else
                            {
                                pt[x, y].Y = 0;
                            }
                        }
                    }

                    Bitmap bSrc = (Bitmap)baseMap.Clone();

                    BitmapData bitmapData = baseMap.LockBits(new Rectangle(0, 0, baseMap.Width, baseMap.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                    BitmapData bmSrc = bSrc.LockBits(new Rectangle(0, 0, bSrc.Width, bSrc.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

                    int scanline = bitmapData.Stride;

                    IntPtr scan0 = bitmapData.Scan0;
                    IntPtr srcScan0 = bmSrc.Scan0;

                    unsafe
                    {
                        byte* p = (byte*)(void*)scan0;
                        byte* pSrc = (byte*)(void*)srcScan0;

                        int nOffset = bitmapData.Stride - baseMap.Width * 3;

                        for (int y = 0; y < nHeight; ++y)
                        {
                            for (int x = 0; x < nWidth; ++x)
                            {
                                var xOffset = pt[x, y].X;
                                var yOffset = pt[x, y].Y;

                                if (yOffset >= 0 && yOffset < nHeight && xOffset >= 0 && xOffset < nWidth)
                                {
                                    if (pSrc != null)
                                    {
                                        p[0] = pSrc[yOffset * scanline + xOffset * 3];
                                        p[1] = pSrc[yOffset * scanline + xOffset * 3 + 1];
                                        p[2] = pSrc[yOffset * scanline + xOffset * 3 + 2];
                                    }
                                }

                                p += 3;
                            }
                            p += nOffset;
                        }
                    }

                    baseMap.UnlockBits(bitmapData);
                    bSrc.UnlockBits(bmSrc);
                    bSrc.Dispose();
                }
            }
        }

三、短信验证码实现:

见上篇:

传送门:基于Aliyun短信验证码实现

四、图片验证码获取与校验:

获取:

代码:

  /// <summary>
        /// 获取图片验证码
        /// </summary>
        /// <param name="imgCaptchaDto">图形验证码请求信息</param>
        [HttpGet("img")]
        public IActionResult GetImageCaptcha([FromQuery]ImgCaptchaDto imgCaptchaDto)
        {
            var result = _captchaService.GetImageCaptcha(imgCaptchaDto);
            var stream = new MemoryStream(result.CaptchaByteData);

            return new FileStreamResult(stream, "image/png");
        }

Http调用:详细调用参数和方式见下方接口在线文档。
image

校验:

代码:

 /// <summary>
        /// 验证图片验证码
        /// </summary>
        /// <param name="imgCaptchaDto">图形验证码信息</param>
        /// <returns></returns>
        [HttpPost("img")]
        public IActionResult ValidateImageCaptcha(ImgCaptchaDto imgCaptchaDto)
        {
            bool isCaptchaValid = _captchaService.ValidateImageCaptcha(imgCaptchaDto);
            if (isCaptchaValid)
            {
                HttpResponseDto httpResponseDto = new HttpResponseDto()
                {
                    IsSuccess = true,
                    Code = StatusCodes.Status200OK,
                    Message = "图形验证码验证成功"
                };
                var responJson = JsonConvert.SerializeObject(httpResponseDto);
                return Ok(responJson);
            }
            else
            {
                HttpResponseDto httpResponseDto = new HttpResponseDto()
                {
                    IsSuccess = false,
                    Code = StatusCodes.Status403Forbidden,
                    Message = "验证失败,请输入正确手机号及获取到的验证码"
                };
                var responJson = JsonConvert.SerializeObject(httpResponseDto);
                return StatusCode(StatusCodes.Status403Forbidden, responJson);
            }
        }

Http调用:详细调用参数和方式见下方接口在线文档。
image

五、短信验证码获取与校验:

获取:

代码:

/// <summary>
        /// 获取短信验证码
        /// </summary>
        /// <param name="msgCaptchaDto">短信验证码请求信息</param>
        /// <returns></returns>
        [HttpGet("msg")]
        public IActionResult GetMsgCaptcha([FromQuery]MsgCaptchaDto msgCaptchaDto)
        {
            var msgSendResult = _captchaService.GetMsgCaptcha(msgCaptchaDto);
            if (msgSendResult.Item1)
            {
                return Ok(msgSendResult.Item2);
            }
            else
            {
                return StatusCode(StatusCodes.Status403Forbidden, msgSendResult.Item2);
            }
        }

Http调用:详细调用参数和方式见下方接口在线文档。
image

image

校验:

代码:

/// <summary>
        /// 验证短信验证码
        /// </summary>
        /// <param name="msgCaptchaDto">短信验证码信息</param>
        /// <returns></returns>
        [HttpPost("msg")]
        public IActionResult ValidateMsgCaptcha(MsgCaptchaDto msgCaptchaDto)
        {
            var validateResult = _captchaService.ValidateMsgCaptcha(msgCaptchaDto);
            if (validateResult.Item1)
            {
                HttpResponseDto httpResponseDto = new HttpResponseDto()
                {
                    IsSuccess = true,
                    Code = StatusCodes.Status200OK,
                    Message = validateResult.Item2
                };
                var responJson = JsonConvert.SerializeObject(httpResponseDto);
                return Ok(responJson);
            }
            else
            {
                HttpResponseDto httpResponseDto = new HttpResponseDto()
                {
                    IsSuccess = false,
                    Code = StatusCodes.Status403Forbidden,
                    Message = validateResult.Item2
                };
                var responJson = JsonConvert.SerializeObject(httpResponseDto);
                return StatusCode(StatusCodes.Status403Forbidden, responJson);
            }
        }

Http调用:详细调用参数和方式见下方接口在线文档。
image

源码链接地址:

Gitee完整实例地址:

https://gitee.com/mingliang_it/Captcha

接口在线文档:

链接地址:

https://console-docs.apipost.cn/preview/82c61b0950bae0c8/924487d25ec3df36

建群声明:本着技术在于分享,方便大家交流学习的初心,特此建立【编程内功修炼交流群】,热烈欢迎各位爱交流学习的程序员进群,也希望进群的大佬能不吝分享自己遇到的技术问题和学习心得。
image

标签:实战,rand,短信,int,验证码,Next,var,new
From: https://www.cnblogs.com/wml-it/p/17617097.html

相关文章

  • 从零玩转系列之微信支付实战PC端项目构建+页面基础搭建 | 技术创作特训营第一期
    一、前言欢迎来到本期的博客!在这篇文章中,我们将带您深入了解前端开发领域中的一个热门话题:如何使用Vue3和Vite构建前端项目。随着现代Web应用程序的需求不断演进,选择适当的工具和技术变得至关重要。Vue3作为一种流行的前端框架,以其出色的性能和灵活的特性赢得了众多开......
  • Python 爬虫实战:驾驭数据洪流,揭秘网页深处
    前言随着互联网的发展,数据变得越来越重要,爬虫技术也越来越受到人们的关注。爬虫技术可以帮助我们自动化地抓取网络数据,从而提高数据的利用价值。但是,在爬虫过程中,很容易被目标网站识别出来,甚至被封禁。所以,使用代理IP是非常重要的一步。本篇文章将介绍如何使用Python编写爬虫,并使......
  • yolov5实战
    目录1.处理数据(1)读入数据和标签(2)Mosaic数据增强(3)数据增强2.构建网络模型(1)Focus层(2)BottleneckCSP层(3)SPP层3.PAN(PathAggregationNetwork)4.损失函数5.预测结果本文使用NEU-DET数据集和yolov5算法对钢材表面的六种常见缺陷进行检测。1.处理数据(1)读入数据和标签......
  • Pytorch框架CV开发-从入门到实战
    点击下载:Pytorch框架CV开发-从入门到实战课程分享,视频+源码+数据集下载!提取码:bbvaPyTorch是一个基于Torch的Python开源机器学习库,用于自然语言处理等应用程序。它主要由Facebookd的人工智能小组开发,不仅能够实现强大的GPU加速,同时还支持动态神经网络,这一点是现在很多主流框架如......
  • hadoop组件---spark实战-----airflow----调度工具airflow定时运行任务的理解
    我们在前面已经初步了解了airflow:hadoop组件—spark实战-----airflow----调度工具airflow的介绍和使用示例但是我们开始尝试使用airflow的定时任务的时候,常常遇到一个尴尬的情况,任务没有成功运行,或者说设置开始时间是今天,但是明天才开始运行。本篇文章尝试说明其中的......
  • hadoop组件---spark实战-----airflow----调度工具airflow部署到k8s中使用
    在之前的文章中我们已经了解了airflow和它的工作原理。hadoop组件—spark实战-----airflow----调度工具airflow的介绍和使用示例Scheduler进程,WebServer进程和Worker进程需要单独启动。Scheduler和WebServer可以跑在一个操作系统内,也可以分开,而通常Worker需要很多,如果是部署特定......
  • hadoop组件---spark实战-----airflow----调度工具airflow的介绍和使用示例
    Airflow是什么Airflow是一个可编程,调度和监控的工作流平台,基于有向无环图(DAG),airflow可以定义一组有依赖的任务,按照依赖依次执行。airflow提供了丰富的命令行工具用于系统管控,而其web管理界面同样也可以方便的管控调度任务,并且对任务运行状态进行实时监控,方便了系统的运维和管理,......
  • MySQL实战面试题
    createdatabasehufei;usehufei;createtableuser_info(idint,device_idint(10),gendervarchar(14),ageint,universityvarchar(32),provincevarchar(32),gpafloat);insertintouser_infovalues(1,2138,'male',21,'北京大学','Beijing&#......
  • redis实战-商城系统
    本文主要基于黑马的redis视频编写redis实战-商城系统短信登录:使用redis共享session来实现商户查询缓存:理解缓存击穿,缓存穿透,缓存雪崩等问题优惠卷秒杀:Redis的计数器功能,结合Lua完成高性能的redis操作,同时了解Redis分布式锁的原理,包括Redis的三种消息队列附近的商户......
  • 【JVM技术指南】「GC内存诊断-故障问题排查」一文教你如何打印及分析JVM的GC日志(实战
    当我们在开发Java应用程序时,JVM的GC(垃圾回收)是一个非常重要的话题。GC的作用是回收不再使用的内存,以便程序可以继续运行。在JVM中,GC的日志记录了GC的详细信息,包括GC的类型、时间、内存使用情况等。在本文中,我们将介绍JVMGC日志的格式、含义和分析方法。JVMGC日志格式JVMGC日志的......