Merhab arkadaşlar,

Bu Asp.Net Mvc(5) uygulamasında 3. parti kütüphane kullanmadan captcha grafiği üretip ilgili form alanında nasıl kullanabiliriz ona bakacağız.

Bunun için bize gerekli olanlar;

  • Asp.Net Mvc 5 uygulaması
  • GDI+
  • Session

Bildiğiniz üzere Captcha kullanmadaki ana hedef, halka açık(public) form alanlarından gelebilecek otomatikleştirilmiş işlemler yada benzeri atakları engellemektir.

Bunun için, sunucu tarafında oluşturulmuş bir takım beş benzemez(rasgele sıralanmış harf rakam karışık) alfanumerik karakterleri okunması hafif zorlaştırılmış bir grafiğe çevirmek ve formu dolduran yaşam formundan talep etmek. Insan olan cevaplar zaten :)

Okunmasını zorlaştırmaktaki amaç yazılımsal olarak çözümlenmesini engellemek.

Alfa numerik karakterlerin oluşturulması.

Basit bir metot ile bu işlemi halledebiliriz diye düşünüyorum.

Tüm karakterleri tek bir string değişkene atayalım. Sayısı kadar bir aralıkta rastgele index değeri üretip bu değer yardımıyla string içinden arka arkaya 5 karakter elde edip bu bahsi kapatalım. Cümleyi neden bu kadar uzattım bilmiyorum.

public static string CreateCaptchaKey()
{
    //kafa karışıklığını engellemek için 0 1 O gibi değeleri eklemedim.
    string chars = "23456789abcdefghjkmnprstuvyzxqw";

    Random rand = new Random();
    string result = "";

    for (int i = 0; i < 5; ++i)
        result += chars[rand.Next(0, chars.Length)].ToString();

    return result;
}
Karakterden resim dosyası oluşturma

Şimdi biraz Gdi+kodlayalım. 

200x80px ebatlarında beyaz bir zemin oluşturalım. Oluşturalım da, bu zemin üzerine karakterleri direk yazdırmak çok mantıklı olmaz. Çok okunaklı olmamalı. Bunun için iki yöntem kullanabiliriz. İlki, teklerde büyük çiftlerde küçük font kullanmak. İkincisi ise, zemin üzerinde farklı noktara 3 adet renkli yuvarlaklar eklemek. Daha ilerisi sizin hayakl gücünüze kalmış.

public static byte[] CreateImage(string key)
{
    Random rnd = new Random();
    Bitmap bmp = new Bitmap(200, 80);
    Graphics g = Graphics.FromImage(bmp);
    g.Clear(Color.White);
    Font f = new Font("Arial", 34, FontStyle.Bold);
    Font fa = new Font("Arial", 18, FontStyle.Bold);
    g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
    g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;

    g.FillEllipse(new SolidBrush(Color.FromArgb(125, 255, 0, 0)), -10, -10, 80, 80);
    g.FillEllipse(new SolidBrush(Color.FromArgb(85, 85, 119, 100)), 60, -10, 60, 60);
    g.FillEllipse(new SolidBrush(Color.FromArgb(161, 173, 185, 9)), 90, 0, 80, 80);

    var colorArray = new Color[] { Color.Red, Color.Green, Color.Blue, Color.Purple, Color.Orange };
    int left = 10;

    for (int i = 0; i < colorArray.Length; i++)
    {
        var color = colorArray[rnd.Next(5)];
        var harf = key[i].ToString();

        if (i % 2 == 0)
        {
            g.RotateTransform(5);
            g.DrawString(harf, f, new SolidBrush(color), left, 10);
        }
        else
        {
            g.RotateTransform(-3);
            g.DrawString(harf, fa, new SolidBrush(color), left, 10);
        }
        left += 30;
    }
    MemoryStream mem = new MemoryStream();
    bmp.Save(mem, ImageFormat.Png);
    return mem.ToArray();
}

Aşağı yukarı şu biçimde bir çıktı olacak.

Captcha

Form içinde grafik dosyasını gösterme

Basit bir form oluşturalım. Burada fazla detaya girmeye gerek yok. Klasik View Model ilişkisi. Önemli olan grafiğin gösterilmesi.

@model Captcha.Kitchen.Models.LoginModel
@using (Html.BeginForm())
{
    <div class="form-group">
        @Html.ValidationSummary(true)
    </div>
    <div class="form-group">
        @Html.LabelFor(p => p.Email)
        @Html.EditorFor(p => p.Email)
        @Html.ValidationMessageFor(p => p.Email)
    </div>
    <div class="form-group">
        @Html.LabelFor(p => p.Password)
        @Html.EditorFor(p => p.Password)
        @Html.ValidationMessageFor(p => p.Password)
    </div>
    <div class="form-group">
        @Html.LabelFor(p => p.Key)
        @Html.EditorFor(p => p.Key)
        @Html.ValidationMessageFor(p => p.Key)
    </div>
    <div class="form-group">
        <img style="cursor:pointer" src="/Home/CreateImage" onclick="reloadR()" class="captcha" />
    </div>
    <button type="submit" class="btn btn-default">Gönder</button>
}
<script>
    //yenilemek için kullanılacak
    function reloadR() {
        $(".captcha").removeAttr("src").attr("src", "/Home/CreateImage?Id=" + Math.floor((Math.random() * 100) + 1));
    }
</script>

Aşağıdaki gibi bir çıktısı olacak.

2018-10-03_11-43-50.png

Sayfa yüklendiğinde img etiketi resmi göstermek için kaynağa başvuracak ve CreateImage Action'ı çalışacak. Önce rastgele karakterler üretilip oturum koleksiyonuna "CaptchaKey" anahtarı ile eklenecek. Daha sonra ise diğer metot çalışarak resim dosyası oluşturacak.

public ActionResult CreateImage()
{
    Session["CaptchaKey"] = CaptchaHelper.CreateCaptchaKey();
    return File(CaptchaHelper.CreateImage(Session["CaptchaKey"].ToString()), "image/png");
}

Kodun tamamına erişmek için, gitlab üzerinden dosyalara ulaşabilirsiniz.