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 :