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


    前言:

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

    一、需求描述:

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

    二、图片验证码实现:

    生成随机验证码字符串:

     /// 
            /// 获取随机验证码
            /// 
            /// 
            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();
            }
    

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

     /// 
            /// 生成随机验证码图片
            /// 
            /// 
            /// 
            /// 
            /// 
            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短信验证码实现

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

    获取:

    代码:

      /// 
            /// 获取图片验证码
            /// 
            /// 图形验证码请求信息
            [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

    校验:

    代码:

     /// 
            /// 验证图片验证码
            /// 
            /// 图形验证码信息
            /// 
            [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

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

    获取:

    代码:

    /// 
            /// 获取短信验证码
            /// 
            /// 短信验证码请求信息
            /// 
            [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

    校验:

    代码:

    /// 
            /// 验证短信验证码
            /// 
            /// 短信验证码信息
            /// 
            [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

  • 相关阅读:
    策略分享|复现经典K线形态:出水芙蓉
    maven内置变量对应的目录
    Java中如何检测一个元素是否存在于HashSet对象中呢?
    【HTML】HTML基础系列文章小小总结,运用标签写出网页!
    matplotlib如何保存高分辨率图(亲测)
    R3Live系列学习(四)R2Live源码阅读(2)
    Anaconda虚拟环境配置Python库与Spyder编译器
    【数据结构】堆排序及TOP-K问题
    AI玩具来了,它怎么样?
    9.4语言是一种实践2
  • 原文地址:https://www.cnblogs.com/wml-it/p/17617097.html