Graphic verification code + SMS verification code practice

Foreword:

The previous article shared an article about SMS verification codes implemented based on Alibaba Cloud. Considering that in order to prevent non-manual operations when logging in, frequently obtaining verification codes and striking while the iron is hot, a picture verification code service function is now added. Drawing on the traditional practice on the Internet, the two verification functions are made into an independent service, and the verification image verification code and SMS verification code are obtained through Http requests respectively.

1. Requirement description:

  • The graphic verification code is, and the SMS verification code is 6 pure numbers.
  • Only one image verification code exists in the cache of the same system and has no validity period. The old graphic verification code is updated every time it is refreshed.
  • SMS verification code is valid for 2 minutes
  • Each mobile phone number can only send an SMS verification code once within 60 seconds, and verification is performed on the server side.
  • The same mobile phone number can have multiple valid SMS verification codes at the same time, which are differentiated according to different system types.
  • Each SMS verification code can be used up to 3 times. Regardless of whether it matches the verification code in the request, it will be invalidated immediately to prevent brute force attacks.
  • Before sending the SMS verification code, first verify whether the graphic verification code is correct.

Second, picture verification code implementation:

Generate random verification code string:

/// <summary>
        /// Get random verification code
        /// </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();
        }

Random verification code generates verification code image:

/// <summary>
        /// Generate a random verification code image
        /// </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 & amp; & amp; newX < nWidth)
                            {
                                pt[x, y].X = (int)newX;
                            }
                            else
                            {
                                pt[x, y].X = 0;
                            }


                            if (newY > 0 & amp; & amp; 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 & amp; & amp; yOffset < nHeight & amp; & amp; xOffset >= 0 & amp; & amp; 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();
                }
            }
        }

3. SMS verification code implementation:

See previous article:

Portal: Based on Aliyun SMS verification code

Four. Picture verification code acquisition and verification:

Get:

Code:

/// <summary>
        /// Get image verification code
        /// </summary>
        /// <param name="imgCaptchaDto">Graphic verification code request information</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 call: For detailed call parameters and methods, please see the interface online documentation below. image

Verification:

Code:

/// <summary>
        ///Verify image verification code
        /// </summary>
        /// <param name="imgCaptchaDto">Graphic verification code information</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 = "Graphic verification code verification successful"
                };
                var responseJson = JsonConvert.SerializeObject(httpResponseDto);
                return Ok(responJson);
            }
            else
            {
                HttpResponseDto httpResponseDto = new HttpResponseDto()
                {
                    IsSuccess = false,
                    Code = StatusCodes.Status403Forbidden,
                    Message = "Verification failed, please enter the correct mobile phone number and verification code obtained"
                };
                var responseJson = JsonConvert.SerializeObject(httpResponseDto);
                return StatusCode(StatusCodes.Status403Forbidden, responJson);
            }
        }

Http call: For detailed call parameters and methods, please see the interface online documentation below. image

5. SMS verification code acquisition and verification:

Get:

Code:

/// <summary>
        /// obtain SMS verification code
        /// </summary>
        /// <param name="msgCaptchaDto">SMS verification code request information</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 call: For detailed call parameters and methods, please see the interface online documentation below. image

image

Verification:

Code:

/// <summary>
        /// Verify SMS verification code
        /// </summary>
        /// <param name="msgCaptchaDto">SMS verification code information</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 responseJson = JsonConvert.SerializeObject(httpResponseDto);
                return Ok(responJson);
            }
            else
            {
                HttpResponseDto httpResponseDto = new HttpResponseDto()
                {
                    IsSuccess = false,
                    Code = StatusCodes.Status403Forbidden,
                    Message = validateResult.Item2
                };
                var responseJson = JsonConvert.SerializeObject(httpResponseDto);
                return StatusCode(StatusCodes.Status403Forbidden, responJson);
            }
        }

Http call: For detailed call parameters and methods, please see the interface online documentation below. image

Gitee complete instance address:

https://gitee.com/mingliang_it/Captcha

Interface online documentation:

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