Imam Ferianto Blogs

sekedar catatan kecil saja

Captcha adalah pengaman form yang bisa berupa rumus matematika, pertanyaan, text, suara, ataupun gambar, ataupun metode lain seperti kuis matching gambar, yang menyakinkan bahwa input dilakukan oleh manusia, bukan robot/bot ataupun otomasi mesin. Ide-nya adalah melindungi form dari otomasi, dengan sesuatu yang secara audio visual dapat diterjemahkan oleh manusia tetapi sulit dimengerti oleh mesin.

Pada sesi kali ini kita akan mencoba membuat captha text dengan menuliskan random text pada Image, harapannya karena ini one time random, maka form akan terproteksi. Seed random text disimpan di server dalam bentuk session yang selanjutkan akan divalidasi pada next process.

Untuk menjalankan captha pada net core 3.0  ini kita perlu menginstall package ImageSharp dengan cara berikut.

dotnet add package SixLabors.ImageSharp --version 1.0.0-rc0002
dotnet add package SixLabors.ImageSharp.Drawing --version 1.0.0-beta0008
dotnet add package SixLabors.Fonts --version 1.0.0-beta0012

Baiklah berikut langsung saja dengan code dan keteranganya (kode telah ditulis ulang dari sample code references).

Data model : CaptchaResult.cs

using System;
using System.Collections.Generic;
using System.IO;

namespace psc.Helper.Captcha
{
	public class CaptchaResult{
                //text dari captha disimpan disini
		public string CaptchaCode { get; set; }

                //byte array dari images
		public byte[] CaptchaByteData { get; set; }
	}

}

 

Captha Utils Generator : Captcha.cs

using System;
using System.Linq;
using System.IO;
using System.Runtime.InteropServices;
using SixLabors.Fonts;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Drawing;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Drawing.Processing;
using System.Numerics;

namespace psc.Helper.Captcha
{
    public class Captcha
    {
                //random generator
		private static Random random = new Random();
   
                //random text function
		public static string RandomString(int length)
		{
                  //random character list
      		  const string chars = "ABCDEFGHIJKLMNPRSTUVWXYZ0123456789";
    		  return new string(Enumerable.Repeat(chars, length)
      		  .Select(s => s[random.Next(s.Length)]).ToArray());
		}

                //generator captcha image
    	       public static CaptchaResult GenerateCaptchaImage(int width, int height, int fontsize){
                  //bikin modelnya
    		  CaptchaResult result=new CaptchaResult();

                  //get random string 5 chars saja
    		  result.CaptchaCode=RandomString(5);

                  //buat base image
      		  using (Image img = new Image<Rgba32>(width, height))
                 {
                         //isi backgroundnya putih aja
                        img.Mutate(ctx => ctx.Fill(Color.White));

                        //list random font
    			var fontFamilies = new string[] { "Arial", "Verdana", "Times New Roman" };

                        //list random colors
    			var fontColors = new Argb32[]{
    				new Argb32(0.0f, 0.0f, 1.0f),
    				new Argb32(0.0f, 0.5f, 0.5f),
    				new Argb32(0.5f, 0.0f, 0.5f),
    				new Argb32(0.8f, 0.8f, 0.0f),
    				new Argb32(1.0f, 0.0f, 0.0f),
    				new Argb32(0.8f, 0.0f, 0.8f)
    			};

                        //list random point untuk membuat efek text miring atau rotate
    			var pointx = new float[]{20,15,10};
               
                        //origin  y,x,p  
    	                float y=5;
    	                int x=0;
            	        int p=0;
             
             	        //loop over chars in randomtext
             	        foreach(char c in result.CaptchaCode){
                           //buat path untuk text flow path
       			   PathBuilder pathBuilder = new PathBuilder();
       			   pathBuilder.SetOrigin(new PointF(y, 20));
                	   pathBuilder.AddBezier(new PointF(y, pointx[random.Next(0,pointx.Length)] ), new PointF(y+20, pointx[random.Next(0,pointx.Length)] ), new PointF(y+80, pointx[random.Next(0,pointx.Length)] ), new PointF(y+100, pointx[random.Next(0,pointx.Length)]) );
                	   y+=20;
       		           IPath path = pathBuilder.Build();

                           //pilih random font
                	  var font = SystemFonts.CreateFont(fontFamilies[random.Next(0,fontFamilies.Length)], fontsize, FontStyle.Regular);  
			    
			    	//set textoption to flow path
			    	var textGraphicsOptions = new TextGraphicsOptions() 
                	{
                    	TextOptions = {WrapTextWidth = path.Length}
                	};

                	//create text glyph
                	var glyphs = TextBuilder.GenerateGlyphs(c.ToString(), path, new RendererOptions(font, textGraphicsOptions.TextOptions.DpiX, textGraphicsOptions.TextOptions.DpiY)
                	{
                    	HorizontalAlignment = textGraphicsOptions.TextOptions.HorizontalAlignment,
                    	TabWidth = textGraphicsOptions.TextOptions.TabWidth,
                    	VerticalAlignment = textGraphicsOptions.TextOptions.VerticalAlignment,
                    	WrappingWidth = textGraphicsOptions.TextOptions.WrapTextWidth,
                    	ApplyKerning = textGraphicsOptions.TextOptions.ApplyKerning
                	});

                	//text color
                	var textcolor= fontColors[random.Next(0,fontColors.Length)];
                	img.Mutate(ctx => ctx
                	.Draw(new Argb32(0.9f, 0.9f, 0.9f), 3, path) //draw path
                    .Fill(textcolor, glyphs)); //draw text

            	}

                SixLabors.ImageSharp.Formats.Png.PngEncoder pngEncoder = new SixLabors.ImageSharp.Formats.Png.PngEncoder();
            	pngEncoder.CompressionLevel = 0;
            	using (var ms = new MemoryStream()){
    				img.Save(ms, pngEncoder);
    				result.CaptchaByteData=ms.ToArray();
				}

            }

            return result;

    	}

    }

 }

 

Penerapannya pada Controller Sebagai berikut (HomeController.cs)

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using psc.Helper.Captcha;
using psc.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using System.IO;

namespace psc.Controllers
{
    public class HomeController : Controller
    {
        private readonly ILogger<HomeController> _logger;

        public HomeController(ILogger<HomeController> logger)
        {
            _logger = logger;
        }

        public IActionResult Index()
        {
            return View();
        }

        //bagian yang menampilkan form dan captha images
        public IActionResult Contact()
        {
            ViewBag.CaptaSalah=false;
            return View();
        }

        //route yang dipanggil untuk menampilkan gambar
        [Route("get-captcha-image")]
        public IActionResult GetCaptchaImage()
        {
            int width = 200;
            int height = 50;
            int fontsize=45;
          
            CaptchaResult result=Captcha.GenerateCaptchaImage(width, height, fontsize);
      
            HttpContext.Session.SetString("CaptchaCode", result.CaptchaCode);
            
            Stream s = new MemoryStream(result.CaptchaByteData);
            return new FileStreamResult(s, "image/png");
      
        }

        //bagian POST yang di proteksi dengan captha
        [HttpPost]
        public ActionResult Contact([Bind("Inquirytype,Sector,Captcha")] ContactForm model)
        {
            if (ModelState.IsValid)
            {  
                String sistemcaptha=HttpContext.Session.GetString("CaptchaCode");
              
                Console.WriteLine("Inquirytype: "+model.Inquirytype);
                Console.WriteLine("Sector: "+model.Sector);
                Console.WriteLine("Captcha Form: "+model.Captcha);
                Console.WriteLine("Capta: "+ sistemcaptha);

                Console.WriteLine("Capta salah\n\n\n\n");

                ViewBag.CaptaSalah=true;

                return View();
            }  
            else
            {  
  

                return View("Terimakasih");
                

            }  
        }


    }
}

Captcha Result:

 

Sumber :