Como criar captcha em Asp.NET C# utilizando MVC 4

0

Captcha são bastante utilizados atualmente no ambiente de desenvolvimento Web. Geralmente Captchas são utilizados para previnir entradas de robots em algum formulário do site.

captcha

captcha

Vamos aprender de forma bastante simplificada um exemplo que você poderá utilizar em seus projetos MVC.
Inicialmente vamos criar uma classe que ficará responsável por gerar uma imagem com dígitos aleatórios, veja:

  public class Captcha
    {
        #region Atributos

        Random rnd = new Random();

        System.Drawing.Brush _color;

        System.Drawing.Brush _backColor;

        int _height;

        int _width;

        int _totalCaracteres;

        bool _numeros;

        System.Drawing.Color _pointColor;

        #endregion

        #region Propriedades

        public int Width
        {
            get { return _width; }
            set { _width = value; }
        }

        public int Height
        {
            get { return _height; }
            set { _height = value; }
        }

        public System.Drawing.Brush BackColor
        {
            get { return _backColor; }
            set { _backColor = value; }
        }

        public System.Drawing.Brush Color
        {
            get { return _color; }
            set { _color = value; }
        }

        public int TotalCaracteres
        {
            get { return _totalCaracteres; }
            set { _totalCaracteres = value; }
        }

        public bool Numeros
        {
            get { return _numeros; }
            set { _numeros = value; }
        }

        public System.Drawing.Color PointColor
        {
            get { return _pointColor; }
            set { _pointColor = value; }
        }

        #endregion

        #region Métodos

        protected string ImageString()
        {
            String valor = "";

            for (int i = 0; i < _totalCaracteres; i++)
            {
                if (rnd.Next(2) == 1 && _numeros)
                    valor += (char)rnd.Next(48, 56);
                else
                    valor += (char)rnd.Next(65, 90);
            }

            return valor;
        }

        public string GeraImage(HttpContext pagina, string imgKey)
        {
            string strValida = imgKey;

            if (string.IsNullOrEmpty(strValida))
                strValida = ImageString();

            pagina.Response.ContentType = "image/jpeg";
            pagina.Response.Clear();
            pagina.Response.BufferOutput = true;

            System.Drawing.Bitmap img = new System.Drawing.Bitmap(_width, _height);
            System.Drawing.Graphics dr = System.Drawing.Graphics.FromImage(img);

            dr.FillRectangle(_backColor, new System.Drawing.Rectangle(0, 0, img.Width, img.Height));

            System.Drawing.Font font = new System.Drawing.Font("Verdana", 18, System.Drawing.FontStyle.Bold);
            dr.DrawString(strValida, font, _color, rnd.Next(20), rnd.Next(_height - 24));

            dr.DrawLine(new System.Drawing.Pen(_color), new System.Drawing.Point(0, rnd.Next(_height)), new System.Drawing.Point(_width, rnd.Next(_height)));
            dr.DrawLine(new System.Drawing.Pen(_color), new System.Drawing.Point(0, rnd.Next(_height)), new System.Drawing.Point(_width, rnd.Next(_height)));
            dr.DrawLine(new System.Drawing.Pen(_color), new System.Drawing.Point(0, rnd.Next(_height)), new System.Drawing.Point(_width, rnd.Next(_height)));
            dr.DrawLine(new System.Drawing.Pen(_color), new System.Drawing.Point(0, rnd.Next(_height)), new System.Drawing.Point(_width, rnd.Next(_height)));
            dr.DrawLine(new System.Drawing.Pen(_color), new System.Drawing.Point(0, rnd.Next(_height)), new System.Drawing.Point(_width, rnd.Next(_height)));
            dr.DrawLine(new System.Drawing.Pen(_color), new System.Drawing.Point(rnd.Next(_width), 0), new System.Drawing.Point(_height, rnd.Next(_width)));
            dr.DrawLine(new System.Drawing.Pen(_color), new System.Drawing.Point(rnd.Next(_width), 0), new System.Drawing.Point(_height, rnd.Next(_width)));
            dr.DrawLine(new System.Drawing.Pen(_color), new System.Drawing.Point(rnd.Next(_width), 0), new System.Drawing.Point(_height, rnd.Next(_width)));
            dr.DrawLine(new System.Drawing.Pen(_color), new System.Drawing.Point(rnd.Next(_width), 0), new System.Drawing.Point(_height, rnd.Next(_width)));
            dr.DrawLine(new System.Drawing.Pen(_color), new System.Drawing.Point(rnd.Next(_width), 0), new System.Drawing.Point(_height, rnd.Next(_width)));


            for (int x = 0; x < img.Width; x++)
                for (int y = 0; y < img.Height; y++)
                    if (rnd.Next(6) == 1)
                        img.SetPixel(x, y, _pointColor);

            font.Dispose();
            dr.Dispose();

            img.Save(pagina.Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg);
            img.Dispose();

            pagina.Response.Write(strValida);
            return strValida;
        }

        public string GeraImage(Page pagina, string imgKey)
        {
            string strValida = imgKey;

            if (string.IsNullOrEmpty(strValida))
                strValida = ImageString();

            pagina.Response.ContentType = "image/jpeg";
            pagina.Response.Clear();
            pagina.Response.BufferOutput = true;

            System.Drawing.Bitmap img = new System.Drawing.Bitmap(_width, _height);
            System.Drawing.Graphics dr = System.Drawing.Graphics.FromImage(img);

            dr.FillRectangle(_backColor, new System.Drawing.Rectangle(0, 0, img.Width, img.Height));

            System.Drawing.Font font = new System.Drawing.Font("Verdana", 18, System.Drawing.FontStyle.Bold);
            dr.DrawString(strValida, font, _color, rnd.Next(20), rnd.Next(_height - 24));

            dr.DrawLine(new System.Drawing.Pen(_color), new System.Drawing.Point(0, rnd.Next(_height)), new System.Drawing.Point(_width, rnd.Next(_height)));
            dr.DrawLine(new System.Drawing.Pen(_color), new System.Drawing.Point(0, rnd.Next(_height)), new System.Drawing.Point(_width, rnd.Next(_height)));
            dr.DrawLine(new System.Drawing.Pen(_color), new System.Drawing.Point(0, rnd.Next(_height)), new System.Drawing.Point(_width, rnd.Next(_height)));
            dr.DrawLine(new System.Drawing.Pen(_color), new System.Drawing.Point(0, rnd.Next(_height)), new System.Drawing.Point(_width, rnd.Next(_height)));
            dr.DrawLine(new System.Drawing.Pen(_color), new System.Drawing.Point(0, rnd.Next(_height)), new System.Drawing.Point(_width, rnd.Next(_height)));
            dr.DrawLine(new System.Drawing.Pen(_color), new System.Drawing.Point(rnd.Next(_width), 0), new System.Drawing.Point(_height, rnd.Next(_width)));
            dr.DrawLine(new System.Drawing.Pen(_color), new System.Drawing.Point(rnd.Next(_width), 0), new System.Drawing.Point(_height, rnd.Next(_width)));
            dr.DrawLine(new System.Drawing.Pen(_color), new System.Drawing.Point(rnd.Next(_width), 0), new System.Drawing.Point(_height, rnd.Next(_width)));
            dr.DrawLine(new System.Drawing.Pen(_color), new System.Drawing.Point(rnd.Next(_width), 0), new System.Drawing.Point(_height, rnd.Next(_width)));
            dr.DrawLine(new System.Drawing.Pen(_color), new System.Drawing.Point(rnd.Next(_width), 0), new System.Drawing.Point(_height, rnd.Next(_width)));


            for (int x = 0; x < img.Width; x++)
                for (int y = 0; y < img.Height; y++)
                    if (rnd.Next(6) == 1)
                        img.SetPixel(x, y, _pointColor);

            font.Dispose();
            dr.Dispose();

            img.Save(pagina.Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg);
            img.Dispose();

            return strValida;
        }



        #endregion
    }
    

Após isto, vamos criar um Generic Handler que ficará responsável por criar uma sessão para o captcha e instanciar as propriedades da imagem.

 public class GerarCaptcha : IHttpHandler, IRequiresSessionState
    {
        private HttpContext _context;
        private Util.Captcha _img;

        public void ProcessRequest(HttpContext context)
        {
            _context = context;
            CriarImagemSafe();
        }

        public bool IsReusable
        {
            get
            {
                return true;
            }
        }

        private bool possoSetarImagem()
        {
            return _context.Session["timeKey"] == null;
        }

        private void SetSessionImgKey(string valor)
        {
            _context.Session["imgKey"] = _img.GeraImage(_context, valor);
        }

        private string GetSessionImgKey()
        {
            return _context.Session["imgKey"] != null ? _context.Session["imgKey"].ToString() : string.Empty;
        }

        private void SetTimeKey()
        {
            _context.Session["timeKey"] = _context.Timestamp;
        }

        private void RemoveTimeKey()
        {
            _context.Session.Remove("timeKey");
        }

        private void CriarImagemSafe()
        {
            _img = new Util.Captcha();
            _img.BackColor = System.Drawing.Brushes.Chocolate;
            _img.Color = System.Drawing.Brushes.White;
            _img.PointColor = System.Drawing.Color.White;

            //Se é pra colocar números no captcha ou não
            _img.Numeros = false;

            _img.TotalCaracteres = 3;
            _img.Height = 61;
            _img.Width = 146;

            ExibirImagem();
        }

        private void ExibirImagem()
        {
            if (possoSetarImagem())
            {
                SetSessionImgKey(string.Empty);
                SetTimeKey();
            }
            else
            {
                RemoveTimeKey();
                SetSessionImgKey(GetSessionImgKey());
            }
        }
    }
    

 

Agora ficou fácil, basta chamar o Handler na sua View !


<img src="@Url.Content("~/GerarCaptcha.ashx")" alt="Image verification" />

<br />
Resultado :  @if (@Session["imgKey"] != null)
             {
    @Session["imgKey"].ToString()
             } 
             

Você poderá utilizar o valor da sessão em sua controller ou como melhor definir para validar a entrada do usuário na sua view.

Você também pode fazer download do projeto aqui : GitHub

 

Gostaria de agradecer também aos 1000 Fans do nosso Facebook que estão nos seguindo! Obrigado! 😀

 

Compartilhe.

Sobre o autor

Criador do blog Código Simples e com mais 9 anos de experiência em TI, com títulos de MVP Microsoft na área de Visual Studio Development, Neo4j Top 50 Certificate, Scrum Master e MongoDB Evangelist. Atuando em funções analista, desenvolvedor, arquiteto, líder técnico e gestor de equipes. Mais informações em : http://jhonathansoares.com