2017年3月15日 星期三

[ASP.NET] Create Captcha to antibot

 ASP.NET MVC     Captcha    C#


Introduction


We will write a simple Captcha image generator and use it in our website.


Environment

Visual Studio 2015 Update 3
APS.NET MVC 5                                  


Implement


Captcha generator

This method will return an object with image byte array and the real captcha text but encrypted.

private Captcha generateCaptcha()
{
            var rand = new Random((int)DateTime.Now.Ticks);
            int rnd = rand.Next(11111, 99999);
            var captchaText = rnd.ToString();

            using (var mem = new MemoryStream())
            using (var bmp = new Bitmap(72, 30))
            using (var gfx = Graphics.FromImage((Image)bmp))
            {
                gfx.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
                gfx.SmoothingMode = SmoothingMode.HighQuality;
                gfx.FillRectangle(Brushes.White, new Rectangle(0, 0, bmp.Width, bmp.Height));
                gfx.Clear(Color.FromArgb(47, 74, 104));

                //Add noise
                int i, r, x, y;
                var pen = new Pen(Color.Yellow);
                for (i = 1; i < 10; i++)
                {
                    pen.Color = Color.FromArgb(
                    (rand.Next(0, 255)),
                    (rand.Next(0, 255)),
                    (rand.Next(0, 255)));

                    r = rand.Next(0, (130 / 3));
                    x = rand.Next(0, 130);
                    y = rand.Next(0, 30);

                    gfx.DrawEllipse(pen, x - r, y - r, r, r);
                }

                //Draw captcha text
                gfx.DrawString(captchaText, new Font("Consolas", 15), Brushes.White, 5, 3);

                //Render as Jpeg
                bmp.Save(mem, System.Drawing.Imaging.ImageFormat.Jpeg);

                var captcha = new Captcha()
                {
                    EncryptedText = MyEncrptFactory.Encrypt(captchaText),
                    ImageBytes = System.Convert.ToBase64String(mem.GetBuffer())
                };
                return captcha;
            }
}



public class Captcha
{
    public string EncryptedText { get; set; }
public string ImageBytes { get; set; }
}


Also create an http method to get the captcha object.

[HttpGet]
public async Task<Captcha> GetCaptcha()
{
     return this.generateCaptcha();
}



Usage

Let’s get the Captcha from backend. (jquery for example)

HTML

<img id="captchaImg" />
<input type="hidden" id="captchaEncryptText" name="captchaEncryptText" />


JS

$.ajax({
        url: getCaptchaUrl,
        type: "GET",
        dataType: "json",
        success: function (captcha) {
            var src = "data:image/png;base64," + captcha.ImageBytes;
            $("#captchaImg").attr("src", src);
            $('#captchaEncryptText').val(captcha.EncryptedText);
        }
});

Notice that if we want to bind the byte array to img:src, append the prefix meta like this:
data:image/png;base64, [image byte array string]

Result:




Now what left is let the user inputs the text which expected to matches our captcha text, and post back the user’s input and the encrypted captcha text to backend for validation.



A more MVC way

We can rewrite our Captcha generator like this and render it on page with Url helper.

MVC : Controller

public ActionResult GenerateCaptcha()
{
//Skip…
               
      //Render as Jpeg
      bmp.Save(mem, System.Drawing.Imaging.ImageFormat.Jpeg);

      FileContentResult img = this.File(mem.GetBuffer(), "image/Jpeg");
}


MVC : View

<img id="captchaImg" src="@Url.Action("GenerateCaptcha ")" />



Reference



沒有留言:

張貼留言