افزودن reCAPTCHA به MVC

داشتن یک کد کپچا از الزامات صفحات ورود می‌باشد. برای پیاده‌سازی Google recaptcha در MVC از روش زیر استفاده کنید:

1- ایجاد HtmlHelper:
این کلاس باکس مربوط به کپچا را نشان می‌دهد.

    public static class GoogleRecaptchaHelper
    {
        /// <summary>
        /// Create recaptcha html helper
        /// </summary>
        /// <param name="helper"></param>
        /// <returns></returns>
        public static IHtmlString GoogleCaptcha(this HtmlHelper helper)
        {
            try
            {
                BLL.Setting.AppSetting_BLL appSettingBLL = new BLL.Setting.AppSetting_BLL();
                var publicKey = appSettingBLL.GetSettingDetails_ById(Domain.Setting.AppSetting_COM.enmSetting.GoogleSiteKey);
                if (publicKey != null)
                {
                    var htmlMvc = new TagBuilder("div")
                    {
                        Attributes =
                        {
                            new System.Collections.Generic.KeyValuePair<string, string>("class","g-recaptcha"),
                            new System.Collections.Generic.KeyValuePair<string, string>("data-sitekey",publicKey.ItemValue)
                        }
                    };
                    const string recaptchaString = @"<script src='https://www.google.com/recaptcha/api.js?hl=fa'></script>";
                    var renderCpatcha = htmlMvc.ToString(TagRenderMode.Normal);

                    return MvcHtmlString.Create($"{recaptchaString}{renderCpatcha}");
                }
                else
                {
                    return null;
                }
            }
            catch
            { return null; }
        }

    }

2- ایجاد HtmlHelper برای نمایش خطا:

    /// <summary>
    /// Creapte recaptcha error message
    /// </summary>
    public static class InvalidGoogleRecaptchaHelper
    {
        public static IHtmlString InvalidRecaptchaLabel(this HtmlHelper helper, string errText)
        {
            var invalidCaptrchaObj = helper.ViewContext.Controller.TempData["InvalidCaptcha"];
            var invalidCaptcha = invalidCaptrchaObj?.ToString();
            if (string.IsNullOrWhiteSpace(invalidCaptcha))
            {
                return MvcHtmlString.Create("");
            }

            var buttonTag = new TagBuilder("span")
            {
                Attributes =
                {
                    new System.Collections.Generic.KeyValuePair<string, string>("class","text text-danger")
                },
                InnerHtml = errText ?? invalidCaptcha
            };

            return MvcHtmlString.Create(buttonTag.ToString(TagRenderMode.Normal));

        }
    }

3- اعتبارسنجی کپچا ارسال شده در کنترلر:

    public class ValidateGoogleCaptchaAttribute : System.Web.Mvc.ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            const string urlToPost = "https://www.google.com/recaptcha/api/siteverify";
            BLL.Setting.AppSetting_BLL appSettingBLL = new BLL.Setting.AppSetting_BLL();
            var secretCode = appSettingBLL.GetSettingDetails_ById(Domain.Setting.AppSetting_COM.enmSetting.GoogleSecretKey);
            if (secretCode != null)
            {
                var cpatchaResponse = filterContext.HttpContext.Request.Form["g-recaptcha-response"];
                if (string.IsNullOrWhiteSpace(cpatchaResponse)) AddErrorAndRedirectToGetAction(filterContext);

                var validateResult = ValidateFromGoogle(urlToPost, secretCode.ItemValue, cpatchaResponse);
                if (!validateResult.Success)
                {
                    AddErrorAndRedirectToGetAction(filterContext);
                }
            }
            base.OnActionExecuting(filterContext);
        }

        private ReCaptchaResponse ValidateFromGoogle(string urlToPost, string secretKey, string captchaResponse)
        {
            var postData = "secret=" + secretKey + "&response=" + captchaResponse;

            var request = (HttpWebRequest)WebRequest.Create(urlToPost);
            request.Method = "POST";
            request.ContentLength = postData.Length;
            request.ContentType = "application/x-www-form-urlencoded";

            using (var streamWriter = new StreamWriter(request.GetRequestStream()))
                streamWriter.Write(postData);

            string result;
            using (var response = (HttpWebResponse)request.GetResponse())
            {
                using (var reader = new StreamReader(response.GetResponseStream()))
                    result = reader.ReadToEnd();
            }

            return JsonConvert.DeserializeObject<ReCaptchaResponse>(result);
        }

        private static void AddErrorAndRedirectToGetAction(ActionExecutingContext filterContext)
        {
            filterContext.Controller.TempData["InvalidCaptcha"] = "گزینه کپچا کد انتخاب نشده!";
            filterContext.Result = new RedirectToRouteResult(filterContext.RouteData.Values);
        }


    }

    internal class ReCaptchaResponse
    {
        [JsonProperty("success")]
        public bool Success { get; set; }

        [JsonProperty("challenge_ts")]
        public string ValidatedDateTime { get; set; }

        [JsonProperty("hostname")]
        public string HostName { get; set; }

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

4- افزودن attribute ساخته شده در مرحله قبل به Action مربوطه:

    [HttpPost]  
    [ValidateAntiForgeryToken]  
    [ValidateGoogleCaptcha]  
    public ActionResult Create(string title)  
    {  
        // If we are here, Captcha is validated.  
        return View();  
    }

5- افزودن Helper به View:

    <div class="form-group">  
        <div class="col-md-offset-2 col-md-10">  
            @Html.GoogleCaptcha()  
            @Html.InvalidGoogleCaptchaLabel("Captcha is not valid !")  
        </div>  
    </div>