翼度科技»论坛 编程开发 .net 查看内容

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

5

主题

5

帖子

15

积分

新手上路

Rank: 1

积分
15
前言:

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


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

生成随机验证码字符串:
  1. /// <summary>
  2.         /// 获取随机验证码
  3.         /// </summary>
  4.         /// <returns></returns>
  5.         public static string GenerateCaptchaCode()
  6.         {
  7.             Random rand = new Random();
  8.             int maxRand = Letters.Length - 1;
  9.             StringBuilder sb = new StringBuilder();
  10.             for (int i = 0; i < 4; i++)
  11.             {
  12.                 int index = rand.Next(maxRand);
  13.                 sb.Append(Letters[index]);
  14.             }
  15.             return sb.ToString();
  16.         }
复制代码
随机验证码生成验证码图片:
  1. /// <summary>
  2.         /// 生成随机验证码图片
  3.         /// </summary>
  4.         /// <param name="width"></param>
  5.         /// <param name="height"></param>
  6.         /// <param name="captchaCode"></param>
  7.         /// <returns></returns>
  8.         public static CaptchaResult GenerateCaptcha(int width, int height, string captchaCode)
  9.         {
  10.             using (Bitmap baseMap = new Bitmap(width, height))
  11.             using (Graphics graph = Graphics.FromImage(baseMap))
  12.             {
  13.                 Random rand = new Random();
  14.                 graph.Clear(GetRandomLightColor());
  15.                 DrawCaptchaCode();
  16.                 DrawDisorderLine();
  17.                 AdjustRippleEffect();
  18.                 MemoryStream ms = new MemoryStream();
  19.                 baseMap.Save(ms, ImageFormat.Png);
  20.                 return new CaptchaResult { CaptchaCode = captchaCode, CaptchaByteData = ms.ToArray(), Timestamp = DateTime.Now };
  21.                 int GetFontSize(int imageWidth, int captchCodeCount)
  22.                 {
  23.                     var averageSize = imageWidth / captchCodeCount;
  24.                     return Convert.ToInt32(averageSize);
  25.                 }
  26.                 Color GetRandomDeepColor()
  27.                 {
  28.                     int redlow = 160, greenLow = 100, blueLow = 160;
  29.                     return Color.FromArgb(rand.Next(redlow), rand.Next(greenLow), rand.Next(blueLow));
  30.                 }
  31.                 Color GetRandomLightColor()
  32.                 {
  33.                     int low = 180, high = 255;
  34.                     int nRend = rand.Next(high) % (high - low) + low;
  35.                     int nGreen = rand.Next(high) % (high - low) + low;
  36.                     int nBlue = rand.Next(high) % (high - low) + low;
  37.                     return Color.FromArgb(nRend, nGreen, nBlue);
  38.                 }
  39.                 void DrawCaptchaCode()
  40.                 {
  41.                     SolidBrush fontBrush = new SolidBrush(Color.Black);
  42.                     int fontSize = GetFontSize(width, captchaCode.Length);
  43.                     Font font = new Font(FontFamily.GenericSerif, fontSize, FontStyle.Bold, GraphicsUnit.Pixel);
  44.                     for (int i = 0; i < captchaCode.Length; i++)
  45.                     {
  46.                         fontBrush.Color = GetRandomDeepColor();
  47.                         int shiftPx = fontSize / 6;
  48.                         //float x = i * fontSize + rand.Next(-shiftPx, shiftPx) + rand.Next(-shiftPx, shiftPx);
  49.                         float x = i * fontSize + rand.Next(-shiftPx, shiftPx) / 2;
  50.                         //int maxY = height - fontSize;
  51.                         int maxY = height - fontSize * 2;
  52.                         if (maxY < 0)
  53.                         {
  54.                             maxY = 0;
  55.                         }
  56.                         float y = rand.Next(0, maxY);
  57.                         graph.DrawString(captchaCode[i].ToString(), font, fontBrush, x, y);
  58.                     }
  59.                 }
  60.                 void DrawDisorderLine()
  61.                 {
  62.                     Pen linePen = new Pen(new SolidBrush(Color.Black), 2);
  63.                     //for (int i = 0; i < rand.Next(3, 5); i++)
  64.                     for (int i = 0; i < 2; i++)
  65.                     {
  66.                         linePen.Color = GetRandomDeepColor();
  67.                         Point startPoint = new Point(rand.Next(0, width), rand.Next(0, height));
  68.                         Point endPoint = new Point(rand.Next(0, width), rand.Next(0, height));
  69.                         graph.DrawLine(linePen, startPoint, endPoint);
  70.                         //Point bezierPoint1 = new Point(rand.Next(0, width), rand.Next(0, height));
  71.                         //Point bezierPoint2 = new Point(rand.Next(0, width), rand.Next(0, height));
  72.                         //graph.DrawBezier(linePen, startPoint, bezierPoint1, bezierPoint2, endPoint);
  73.                     }
  74.                 }
  75.                 void AdjustRippleEffect()
  76.                 {
  77.                     short nWave = 6;
  78.                     int nWidth = baseMap.Width;
  79.                     int nHeight = baseMap.Height;
  80.                     Point[,] pt = new Point[nWidth, nHeight];
  81.                     for (int x = 0; x < nWidth; ++x)
  82.                     {
  83.                         for (int y = 0; y < nHeight; ++y)
  84.                         {
  85.                             var xo = nWave * Math.Sin(2.0 * 3.1415 * y / 128.0);
  86.                             var yo = nWave * Math.Cos(2.0 * 3.1415 * x / 128.0);
  87.                             var newX = x + xo;
  88.                             var newY = y + yo;
  89.                             if (newX > 0 && newX < nWidth)
  90.                             {
  91.                                 pt[x, y].X = (int)newX;
  92.                             }
  93.                             else
  94.                             {
  95.                                 pt[x, y].X = 0;
  96.                             }
  97.                             if (newY > 0 && newY < nHeight)
  98.                             {
  99.                                 pt[x, y].Y = (int)newY;
  100.                             }
  101.                             else
  102.                             {
  103.                                 pt[x, y].Y = 0;
  104.                             }
  105.                         }
  106.                     }
  107.                     Bitmap bSrc = (Bitmap)baseMap.Clone();
  108.                     BitmapData bitmapData = baseMap.LockBits(new Rectangle(0, 0, baseMap.Width, baseMap.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
  109.                     BitmapData bmSrc = bSrc.LockBits(new Rectangle(0, 0, bSrc.Width, bSrc.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
  110.                     int scanline = bitmapData.Stride;
  111.                     IntPtr scan0 = bitmapData.Scan0;
  112.                     IntPtr srcScan0 = bmSrc.Scan0;
  113.                     unsafe
  114.                     {
  115.                         byte* p = (byte*)(void*)scan0;
  116.                         byte* pSrc = (byte*)(void*)srcScan0;
  117.                         int nOffset = bitmapData.Stride - baseMap.Width * 3;
  118.                         for (int y = 0; y < nHeight; ++y)
  119.                         {
  120.                             for (int x = 0; x < nWidth; ++x)
  121.                             {
  122.                                 var xOffset = pt[x, y].X;
  123.                                 var yOffset = pt[x, y].Y;
  124.                                 if (yOffset >= 0 && yOffset < nHeight && xOffset >= 0 && xOffset < nWidth)
  125.                                 {
  126.                                     if (pSrc != null)
  127.                                     {
  128.                                         p[0] = pSrc[yOffset * scanline + xOffset * 3];
  129.                                         p[1] = pSrc[yOffset * scanline + xOffset * 3 + 1];
  130.                                         p[2] = pSrc[yOffset * scanline + xOffset * 3 + 2];
  131.                                     }
  132.                                 }
  133.                                 p += 3;
  134.                             }
  135.                             p += nOffset;
  136.                         }
  137.                     }
  138.                     baseMap.UnlockBits(bitmapData);
  139.                     bSrc.UnlockBits(bmSrc);
  140.                     bSrc.Dispose();
  141.                 }
  142.             }
  143.         }
复制代码
三、短信验证码实现:

见上篇:

传送门:基于Aliyun短信验证码实现
四、图片验证码获取与校验:

获取:

代码:
  1.   /// <summary>
  2.         /// 获取图片验证码
  3.         /// </summary>
  4.         /// <param name="imgCaptchaDto">图形验证码请求信息</param>
  5.         [HttpGet("img")]
  6.         public IActionResult GetImageCaptcha([FromQuery]ImgCaptchaDto imgCaptchaDto)
  7.         {
  8.             var result = _captchaService.GetImageCaptcha(imgCaptchaDto);
  9.             var stream = new MemoryStream(result.CaptchaByteData);
  10.             return new FileStreamResult(stream, "image/png");
  11.         }
复制代码
Http调用:详细调用参数和方式见下方接口在线文档。

校验:

代码:
  1. /// <summary>
  2.         /// 验证图片验证码
  3.         /// </summary>
  4.         /// <param name="imgCaptchaDto">图形验证码信息</param>
  5.         /// <returns></returns>
  6.         [HttpPost("img")]
  7.         public IActionResult ValidateImageCaptcha(ImgCaptchaDto imgCaptchaDto)
  8.         {
  9.             bool isCaptchaValid = _captchaService.ValidateImageCaptcha(imgCaptchaDto);
  10.             if (isCaptchaValid)
  11.             {
  12.                 HttpResponseDto httpResponseDto = new HttpResponseDto()
  13.                 {
  14.                     IsSuccess = true,
  15.                     Code = StatusCodes.Status200OK,
  16.                     Message = "图形验证码验证成功"
  17.                 };
  18.                 var responJson = JsonConvert.SerializeObject(httpResponseDto);
  19.                 return Ok(responJson);
  20.             }
  21.             else
  22.             {
  23.                 HttpResponseDto httpResponseDto = new HttpResponseDto()
  24.                 {
  25.                     IsSuccess = false,
  26.                     Code = StatusCodes.Status403Forbidden,
  27.                     Message = "验证失败,请输入正确手机号及获取到的验证码"
  28.                 };
  29.                 var responJson = JsonConvert.SerializeObject(httpResponseDto);
  30.                 return StatusCode(StatusCodes.Status403Forbidden, responJson);
  31.             }
  32.         }
复制代码
Http调用:详细调用参数和方式见下方接口在线文档。

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

获取:

代码:
  1. /// <summary>
  2.         /// 获取短信验证码
  3.         /// </summary>
  4.         /// <param name="msgCaptchaDto">短信验证码请求信息</param>
  5.         /// <returns></returns>
  6.         [HttpGet("msg")]
  7.         public IActionResult GetMsgCaptcha([FromQuery]MsgCaptchaDto msgCaptchaDto)
  8.         {
  9.             var msgSendResult = _captchaService.GetMsgCaptcha(msgCaptchaDto);
  10.             if (msgSendResult.Item1)
  11.             {
  12.                 return Ok(msgSendResult.Item2);
  13.             }
  14.             else
  15.             {
  16.                 return StatusCode(StatusCodes.Status403Forbidden, msgSendResult.Item2);
  17.             }
  18.         }
复制代码
Http调用:详细调用参数和方式见下方接口在线文档。


校验:

代码:
  1. /// <summary>
  2.         /// 验证短信验证码
  3.         /// </summary>
  4.         /// <param name="msgCaptchaDto">短信验证码信息</param>
  5.         /// <returns></returns>
  6.         [HttpPost("msg")]
  7.         public IActionResult ValidateMsgCaptcha(MsgCaptchaDto msgCaptchaDto)
  8.         {
  9.             var validateResult = _captchaService.ValidateMsgCaptcha(msgCaptchaDto);
  10.             if (validateResult.Item1)
  11.             {
  12.                 HttpResponseDto httpResponseDto = new HttpResponseDto()
  13.                 {
  14.                     IsSuccess = true,
  15.                     Code = StatusCodes.Status200OK,
  16.                     Message = validateResult.Item2
  17.                 };
  18.                 var responJson = JsonConvert.SerializeObject(httpResponseDto);
  19.                 return Ok(responJson);
  20.             }
  21.             else
  22.             {
  23.                 HttpResponseDto httpResponseDto = new HttpResponseDto()
  24.                 {
  25.                     IsSuccess = false,
  26.                     Code = StatusCodes.Status403Forbidden,
  27.                     Message = validateResult.Item2
  28.                 };
  29.                 var responJson = JsonConvert.SerializeObject(httpResponseDto);
  30.                 return StatusCode(StatusCodes.Status403Forbidden, responJson);
  31.             }
  32.         }
复制代码
Http调用:详细调用参数和方式见下方接口在线文档。

源码链接地址:

Gitee完整实例地址:

https://gitee.com/mingliang_it/Captcha
接口在线文档:

链接地址:

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


来源:https://www.cnblogs.com/wml-it/archive/2023/08/09/17617097.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具