MVC’de Invisible reCAPTCHA Kullanımı

MVC’de Invisible reCAPTCHA Kullanımı

Selamlar,

Google reCAPTCHA için spam ve bot’ları durdurmak için en çok kullanılan captcha diyebilirim. Invisible reCAPTCHA kullanıcıya herhangi bir checkbox işaretlemesine gerek kalmadan sitenize entegre edebileceğiniz yeni bir reCAPTCHA çeşidi. Hakkındaki kısa tanıtım videosu ise şu şekilde;

Bu yazımda Invisible reCAPTCHA’nın MVC ile entegrasyonu’nu nasıl yapılacağını anlatacağım.

Öncelikle reCAPTCHA entegre edeceğimiz projeyi oluşturmamız gerekiyor.

File > New > Project seçeneği ile yeni bir ASP.NET Web Application oluşturuyoruz

Makalemde kullanmak üzere belirli kodların hazır gelmesi için MVC template’ini seçerek devam ediyorum.

Proje oluşturuldukdan sonra Register ekranına Invisible reCAPTCHA entegre etmek üzere düzenlemelere başlıyoruz.

Not: Bu adımdan sonraki işlemlerde bu adresten kayıt olarak reCAPTCHA keylerinizi almanız gerekiyor.

İlk olarak Views\Shared\_Layout.cshtml dosyasında head tag’leri arasına reCAPTCHA core js dosyasını ekliyoruz.

<script src="https://www.google.com/recaptcha/api.js" async defer></script>

Sıra Views\Account\Register.cshtml dosyasına yapacağımız değişikliklerde. Sayfada bulunan form’a “registerForm” id’sini ekliyoruz.

@using (Html.BeginForm("Register", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form", id = "registerForm" }))

reCAPTCHA render edilebilmesi için register butonunda bir kaç değişiklik yapmamız gerekiyor. g-recaptcha Class’ını, data-sitekey ve data-callback attribute’lerini ekliyoruz.
data-sitekey aldığımız api key sonrası google tarafından veriliyor.
data-callback ise doğrulama sonuçlanınca tetiklenecek js method’umuz.
Ek olarak birde validasyon işlemlerimiz için onclick=”validate();” attribute ekliyoruz.

Register butonunun Önceki hali;

<input type="submit" class="btn btn-default" value="Register" />

Sonraki hali;

<input type="submit" class="btn btn-default g-recaptcha" data-sitekey="xxxBuraSiteKeyEklenecekxxx" onclick="validate();" data-callback='onSubmit' value="Register" />

reCAPTCHA özel js kodlarımızı yazmak için Scripts klasörünün içerisine reCaptcha adında bir js file oluştuyoruz.

function onSubmit(token) {
    $("#registerForm").submit();
}

function validate() {
    if (grecaptcha.getResponse() != "") {
        $("#registerForm").submit();
    }
}

Oluşturduğumuz js dosyasını register view’ı üzerinden çağırmamız gerekiyor bu işlem için sayfada bulunan section’a ekleme yapıyoruz.

<script src="~/Scripts/reCaptcha.js" type="text/javascript"></script>

Front-end’de yapacaklarımız bu kadar Register.cshtml son hali şu şekilde olması gerekiyor

@model InvisibleReCAPTCHA.Models.RegisterViewModel
@{
    ViewBag.Title = "Register";
}

<h2>@ViewBag.Title.</h2>

@using (Html.BeginForm("Register", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form", id = "registerForm" }))
{
    @Html.AntiForgeryToken()
    <h4>Create a new account.</h4>
    <hr />
    @Html.ValidationSummary("", new { @class = "text-danger" })
    <div class="form-group">
        @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            @Html.TextBoxFor(m => m.Email, new { @class = "form-control" })
        </div>
    </div>
    <div class="form-group">
        @Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            @Html.PasswordFor(m => m.Password, new { @class = "form-control" })
        </div>
    </div>
    <div class="form-group">
        @Html.LabelFor(m => m.ConfirmPassword, new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" })
        </div>
    </div>
    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" class="btn btn-default g-recaptcha" data-sitekey="xxxBuraSiteKeyEklenecekxxx" onclick="validate();" data-callback='onSubmit' value="Register" />
        </div>
    </div>
}

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
    <script src="~/Scripts/reCaptcha.js" type="text/javascript"></script>
}

Şimdi gelelim Back-end tarafında yapcağımız değişikliklere. Back-end’de Request param. ile gelen g-Recaptcha-Response değerini reCAPTCHA’ya eklediğimiz site ile bize berilen SecretKey ile birlikte reCAPTCHA api’sine istek atmamız gerekiyor. Api bize result olarak 4 adet değer dönüyor.

{
  "success": true|false,
  "challenge_ts": timestamp,  // timestamp of the challenge load (ISO format yyyy-MM-dd'T'HH:mm:ssZZ)
  "hostname": string,         // the hostname of the site where the reCAPTCHA was solved
  "error-codes": [...]        // optional
}

Bizde istek sonucunu parse etmek için kullanacağımız ReCaptchaResult class’ını Models klasörüne ekleyerek başlıyoruz.

using System.Collections.Generic;
using Newtonsoft.Json;

namespace InvisibleReCAPTCHA.Models
{
    public class ReCaptchaResult
    {
        [JsonProperty("success")]
        public bool Success { get; set; }

        [JsonProperty("error-codes")]
        public List<string> ErrorCodes { get; set; }
    }
}

Sonrasında AccountController içerisindeki Register method’una google api isteğini yapacağımız bloğu ekliyoruz.

try
                {
                    using (WebClient client = new WebClient())
                    {
                        var response =
                            client.DownloadString(
                                string.Format("https://www.google.com/recaptcha/api/siteverify?secret={0}&response={1}",
                                    "xxxBurayaSecretKeyEklenecekxxx", Request.Params["g-Recaptcha-Response"]));

                        ReCaptchaResult reCaptchaResult = JsonConvert.DeserializeObject<ReCaptchaResult>(response);

                        if (!reCaptchaResult.Success)
                        {
                            ModelState.AddModelError("reCaptcha", "Bot olmadığınızı kanıtlayın.");
                            return View(model);
                        }
                    }
                }
                catch (Exception exception)
                {
                    ModelState.AddModelError("reCaptcha", exception);
                    return View(model);
                }

Bu kod bloğu reCAPTCHA api’sine yapılan isteğin sonucunu parse ettikten sonra eğer sonuç false ise veya istek atarken bir exception alırsak ModelState yeni bir Error ekleyerek geri dönüyoruz.

Register method’umuzun son hali şu şekilde;

        //
        // POST: /Account/Register
        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> Register(RegisterViewModel model)
        {
            if (ModelState.IsValid)
            {
                try
                {
                    using (WebClient client = new WebClient())
                    {
                        var response =
                            client.DownloadString(
                                string.Format("https://www.google.com/recaptcha/api/siteverify?secret={0}&response={1}",
                                    "xxxBurayaSecretKeyEklenecekxxx", Request.Params["g-Recaptcha-Response"]));

                        ReCaptchaResult reCaptchaResult = JsonConvert.DeserializeObject<ReCaptchaResult>(response);

                        if (!reCaptchaResult.Success)
                        {
                            ModelState.AddModelError("reCaptcha", "Bot olmadığınızı kanıtlayın.");
                            return View(model);
                        }
                    }
                }
                catch (Exception exception)
                {
                    ModelState.AddModelError("reCaptcha", exception);
                    return View(model);
                }

                var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
                var result = await UserManager.CreateAsync(user, model.Password);
                if (result.Succeeded)
                {
                    await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false);
                    
                    // For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771
                    // Send an email with this link
                    // string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
                    // var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
                    // await UserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking <a href=\"" + callbackUrl + "\">here</a>");

                    return RedirectToAction("Index", "Home");
                }
                AddErrors(result);
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }

Projeyi derleyip ilk denememizi yapabiliriz.

Gördüğünüz gibi kullanıcı hiçbir checkbox tıklamadan kayıt olabildi. 😉

Şimdi birde diğer senaryoyu deneyelim.

Eğer js tarafında ki yapılan reCAPTCHA isteğinde birşeyler ters giderse direk reCAPTCHA paneli açılıyor ve kullanıcının seçim yapılması isteniyor.

İşte bu kadar ? Invisible reCAPTCHA entegrasyonunu tamamlamış olduk.

Beğendiyseniz paylaşmaktan, takıldığınız bir nokta var ise soru sormaktan çekinmeyin 🙂

Görüşmek üzere!

Source Code : https://github.com/mehmetcakmaz/InvisibleReCAPTCHASample

  1. Tebrikler Mehmet, gayet faydalı bir çalışma olmuş, genç developer’ lar için iyi bir kaynak. Eline sağlık.

      1. Selam, konu eski ama belki dönersiniz. Gizli veya değil tek Api ile bir çok farklı sitede recaptcha kullanılabilir mi?

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Sonraki:

Swagger UI Nedir, Nasıl Kurulur?

Swagger UI Nedir, Nasıl Kurulur?