Jak zaimplementować reCaptcha w ASP.NET MVC i C #?
c#
asp.net
asp.net-mvc-2
xport
źródło
źródło
Odpowiedzi:
Jest kilka świetnych przykładów:
Zostało to również omówione wcześniej w tym pytaniu o przepełnienie stosu .
NuGet Google reCAPTCHA V2 dla MVC 4 i 5
źródło
Recaptcha.dll
? Zespół Google?Dodałem reCaptcha do projektu, nad którym obecnie pracuję. Potrzebowałem go do korzystania z API AJAX, ponieważ element reCaptcha był ładowany dynamicznie na stronę. Nie mogłem znaleźć żadnych istniejących kontrolek, a interfejs API jest prosty, więc utworzyłem własne.
Prześlę tutaj swój kod na wypadek, gdyby ktoś uznał go za przydatny.
1: Dodaj tag script do nagłówków strony wzorcowej
<script type="text/javascript" src="http://www.google.com/recaptcha/api/js/recaptcha_ajax.js"></script>
2: Dodaj klucze do pliku web.config
<appSettings> <add key="ReCaptcha.PrivateKey" value="[key here]" /> <add key="ReCaptcha.PublicKey" value="[key here]" /> </appSettings>
3: Utwórz rozszerzenie Action Attribute i Html Helper
namespace [Your chosen namespace].ReCaptcha { public enum Theme { Red, White, BlackGlass, Clean } [Serializable] public class InvalidKeyException : ApplicationException { public InvalidKeyException() { } public InvalidKeyException(string message) : base(message) { } public InvalidKeyException(string message, Exception inner) : base(message, inner) { } } public class ReCaptchaAttribute : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext filterContext) { var userIP = filterContext.RequestContext.HttpContext.Request.UserHostAddress; var privateKey = ConfigurationManager.AppSettings.GetString("ReCaptcha.PrivateKey", ""); if (string.IsNullOrWhiteSpace(privateKey)) throw new InvalidKeyException("ReCaptcha.PrivateKey missing from appSettings"); var postData = string.Format("&privatekey={0}&remoteip={1}&challenge={2}&response={3}", privateKey, userIP, filterContext.RequestContext.HttpContext.Request.Form["recaptcha_challenge_field"], filterContext.RequestContext.HttpContext.Request.Form["recaptcha_response_field"]); var postDataAsBytes = Encoding.UTF8.GetBytes(postData); // Create web request var request = WebRequest.Create("http://www.google.com/recaptcha/api/verify"); request.Method = "POST"; request.ContentType = "application/x-www-form-urlencoded"; request.ContentLength = postDataAsBytes.Length; var dataStream = request.GetRequestStream(); dataStream.Write(postDataAsBytes, 0, postDataAsBytes.Length); dataStream.Close(); // Get the response. var response = request.GetResponse(); using (dataStream = response.GetResponseStream()) { using (var reader = new StreamReader(dataStream)) { var responseFromServer = reader.ReadToEnd(); if (!responseFromServer.StartsWith("true")) ((Controller)filterContext.Controller).ModelState.AddModelError("ReCaptcha", "Captcha words typed incorrectly"); } } } } public static class HtmlHelperExtensions { public static MvcHtmlString GenerateCaptcha(this HtmlHelper helper, Theme theme, string callBack = null) { const string htmlInjectString = @"<div id=""recaptcha_div""></div> <script type=""text/javascript""> Recaptcha.create(""{0}"", ""recaptcha_div"", {{ theme: ""{1}"" {2}}}); </script>"; var publicKey = ConfigurationManager.AppSettings.GetString("ReCaptcha.PublicKey", ""); if (string.IsNullOrWhiteSpace(publicKey)) throw new InvalidKeyException("ReCaptcha.PublicKey missing from appSettings"); if (!string.IsNullOrWhiteSpace(callBack)) callBack = string.Concat(", callback: ", callBack); var html = string.Format(htmlInjectString, publicKey, theme.ToString().ToLower(), callBack); return MvcHtmlString.Create(html); } } }
4: Dodaj captcha do swojego widoku
@using (Html.BeginForm("MyAction", "MyController")) { @Html.TextBox("EmailAddress", Model.EmailAddress) @Html.GenerateCaptcha(Theme.White) <input type="submit" value="Submit" /> }
5: Dodaj atrybut do swojej akcji
[HttpPost] [ReCaptcha] public ActionResult MyAction(MyModel model) { if (!ModelState.IsValid) // Will have a Model Error "ReCaptcha" if the user input is incorrect return Json(new { capthcaInvalid = true }); ... other stuff ... }
6: Pamiętaj, że będziesz musiał ponownie załadować captcha po każdym poście, nawet jeśli był ważny, a inna część formularza była nieprawidłowa. Posługiwać się
Recaptcha.reload();
źródło
Proste i kompletne rozwiązanie pracujące dla mnie. Obsługuje ASP.NET MVC 4 i 5 (obsługuje ASP.NET 4.0, 4.5 i 4.5.1)
Krok 1. Zainstaluj pakiet NuGet za pomocą polecenia „ Zainstaluj pakiet reCAPTCH.MVC ”
Krok 2: Dodaj swój klucz publiczny i prywatny do pliku web.config w sekcji appsettings
<appSettings> <add key="ReCaptchaPrivateKey" value=" -- PRIVATE_KEY -- " /> <add key="ReCaptchaPublicKey" value=" -- PUBLIC KEY -- " /> </appSettings>
Możesz utworzyć parę kluczy API dla swojej witryny pod adresem https://www.google.com/recaptcha/intro/index.html i kliknąć Pobierz reCAPTCHA u góry strony
Krok 3: Zmodyfikuj swój formularz, aby zawierał reCaptcha
@using reCAPTCHA.MVC @using (Html.BeginForm()) { @Html.Recaptcha() @Html.ValidationMessage("ReCaptcha") <input type="submit" value="Register" /> }
Krok 4 : Zaimplementuj akcję kontrolera, która będzie obsługiwać przesyłanie formularza i weryfikację Captcha
[CaptchaValidator( PrivateKey = "your private reCaptcha Google Key", ErrorMessage = "Invalid input captcha.", RequiredMessage = "The captcha field is required.")] public ActionResult MyAction(myVM model) { if (ModelState.IsValid) //this will take care of captcha { } }
LUB
public ActionResult MyAction(myVM model, bool captchaValid) { if (captchaValid) //manually check for captchaValid { } }
źródło
Uncaught Error: ReCAPTCHA placeholder element must be empty
.PrivateKey = "your private reCaptcha Google Key"
. Jest to o wiele łatwiejsze, gdy masz różne klawisze dla różnych środowiskWersja asynchroniczna dla MVC 5 (tj. Unikanie ActionFilterAttribute, która nie jest asynchroniczna do MVC 6) i reCAPTCHA 2
ExampleController.cs
public class HomeController : Controller { [HttpPost] [ValidateAntiForgeryToken] public async Task<ActionResult> ContactSubmit( [Bind(Include = "FromName, FromEmail, FromPhone, Message, ContactId")] ContactViewModel model) { if (!await RecaptchaServices.Validate(Request)) { ModelState.AddModelError(string.Empty, "You have not confirmed that you are not a robot"); } if (ModelState.IsValid) { ...
ExampleView.cshtml
@model MyMvcApp.Models.ContactViewModel @*This is assuming the master layout places the styles section within the head tags*@ @section Styles { @Styles.Render("~/Content/ContactPage.css") <script src='https://www.google.com/recaptcha/api.js'></script> } @using (Html.BeginForm("ContactSubmit", "Home",FormMethod.Post, new { id = "contact-form" })) { @Html.AntiForgeryToken() ... <div class="form-group"> @Html.LabelFor(m => m.Message) @Html.TextAreaFor(m => m.Message, new { @class = "form-control", @cols = "40", @rows = "3" }) @Html.ValidationMessageFor(m => m.Message) </div> <div class="row"> <div class="g-recaptcha" data-sitekey='@System.Configuration.ConfigurationManager.AppSettings["RecaptchaClientKey"]'></div> </div> <div class="row"> <input type="submit" id="submit-button" class="btn btn-default" value="Send Your Message" /> </div> }
RecaptchaServices.cs
using System; using System.Collections.Generic; using System.Threading.Tasks; using System.Web; using System.Configuration; using System.Net.Http; using System.Net.Http.Headers; using Newtonsoft.Json; using System.Runtime.Serialization; namespace MyMvcApp.Services { public class RecaptchaServices { //ActionFilterAttribute has no async for MVC 5 therefore not using as an actionfilter attribute - needs revisiting in MVC 6 internal static async Task<bool> Validate(HttpRequestBase request) { string recaptchaResponse = request.Form["g-recaptcha-response"]; if (string.IsNullOrEmpty(recaptchaResponse)) { return false; } using (var client = new HttpClient { BaseAddress = new Uri("https://www.google.com") }) { client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); var content = new FormUrlEncodedContent(new[] { new KeyValuePair<string, string>("secret", ConfigurationManager.AppSettings["RecaptchaSecret"]), new KeyValuePair<string, string>("response", recaptchaResponse), new KeyValuePair<string, string>("remoteip", request.UserHostAddress) }); var result = await client.PostAsync("/recaptcha/api/siteverify", content); result.EnsureSuccessStatusCode(); string jsonString = await result.Content.ReadAsStringAsync(); var response = JsonConvert.DeserializeObject<RecaptchaResponse>(jsonString); return response.Success; } } [DataContract] internal class RecaptchaResponse { [DataMember(Name = "success")] public bool Success { get; set; } [DataMember(Name = "challenge_ts")] public DateTime ChallengeTimeStamp { get; set; } [DataMember(Name = "hostname")] public string Hostname { get; set; } [DataMember(Name = "error-codes")] public IEnumerable<string> ErrorCodes { get; set; } } } }
web.config
<configuration> <appSettings> <!--recaptcha--> <add key="RecaptchaSecret" value="***secret key from https://developers.google.com/recaptcha***" /> <add key="RecaptchaClientKey" value="***client key from https://developers.google.com/recaptcha***" /> </appSettings> </configuration>
źródło
Krok 1: Integracja witryny klienta
Wklej ten fragment przed zamykającym
</head>
tagiem w szablonie HTML:<script src='https://www.google.com/recaptcha/api.js'></script>
Wklej ten fragment na końcu miejsca, w
<form>
którym ma się pojawić widżet reCAPTCHA:<div class="g-recaptcha" data-sitekey="your-site-key"></div>
Krok 2: Integracja z serwerem
Gdy Twoi użytkownicy prześlą formularz, w którym zintegrowałeś reCAPTCHA, jako część ładunku otrzymasz ciąg o nazwie „g-recaptcha-response”. Aby sprawdzić, czy Google zweryfikował tego użytkownika, wyślij żądanie POST z następującymi parametrami:
URL: https://www.google.com/recaptcha/api/siteverify
sekret: Twój tajny klucz
odpowiedź: wartość „g-recaptcha-response”.
Teraz w akcji Twojej aplikacji MVC:
// return ActionResult if you want public string RecaptchaWork() { // Get recaptcha value var r = Request.Params["g-recaptcha-response"]; // ... validate null or empty value if you want // then // make a request to recaptcha api using (var wc = new WebClient()) { var validateString = string.Format( "https://www.google.com/recaptcha/api/siteverify?secret={0}&response={1}", "your_secret_key", // secret recaptcha key r); // recaptcha value // Get result of recaptcha var recaptcha_result = wc.DownloadString(validateString); // Just check if request make by user or bot if (recaptcha_result.ToLower().Contains("false")) { return "recaptcha false"; } } // Do your work if request send from human :) }
źródło
Z powodzeniem wdrożyłem ReCaptcha w następujący sposób.
uwaga: to jest w VB, ale można je łatwo przekonwertować
1] Najpierw pobierz kopię biblioteki reCaptcha
2] Następnie utwórz niestandardowy pomocnik ReCaptcha HTML Helper
''# fix SO code coloring issue. <Extension()> Public Function reCaptcha(ByVal htmlHelper As HtmlHelper) As MvcHtmlString Dim captchaControl = New Recaptcha.RecaptchaControl With {.ID = "recaptcha", .Theme = "clean", .PublicKey = "XXXXXX", .PrivateKey = "XXXXXX"} Dim htmlWriter = New HtmlTextWriter(New IO.StringWriter) captchaControl.RenderControl(htmlWriter) Return MvcHtmlString.Create(htmlWriter.InnerWriter.ToString) End Function
3] Stąd potrzebujesz walidatora po stronie serwera, który może być ponownie użyty
Public Class ValidateCaptchaAttribute : Inherits ActionFilterAttribute Private Const CHALLENGE_FIELD_KEY As String = "recaptcha_challenge_field" Private Const RESPONSE_FIELD_KEY As String = "recaptcha_response_field" Public Overrides Sub OnActionExecuting(ByVal filterContext As ActionExecutingContext) If IsNothing(filterContext.HttpContext.Request.Form(CHALLENGE_FIELD_KEY)) Then ''# this will push the result value into a parameter in our Action filterContext.ActionParameters("CaptchaIsValid") = True Return End If Dim captchaChallengeValue = filterContext.HttpContext.Request.Form(CHALLENGE_FIELD_KEY) Dim captchaResponseValue = filterContext.HttpContext.Request.Form(RESPONSE_FIELD_KEY) Dim captchaValidtor = New RecaptchaValidator() With {.PrivateKey = "xxxxx", .RemoteIP = filterContext.HttpContext.Request.UserHostAddress, .Challenge = captchaChallengeValue, .Response = captchaResponseValue} Dim recaptchaResponse = captchaValidtor.Validate() ''# this will push the result value into a parameter in our Action filterContext.ActionParameters("CaptchaIsValid") = recaptchaResponse.IsValid MyBase.OnActionExecuting(filterContext) End Sub
powyżej tej linii jest kod wielokrotnego użytku ** ONE TIME **
poniżej tej linii widać, jak łatwo jest wielokrotnie wdrażać reCaptcha
Teraz, gdy masz już kod wielokrotnego użytku ... wszystko, co musisz zrobić, to dodać captcha do swojego widoku.
A kiedy wyślesz formularz do swojego kontrolera ...
''# Fix SO code coloring issues <ValidateCaptcha()> <AcceptVerbs(HttpVerbs.Post)> Function Add(ByVal CaptchaIsValid As Boolean, ByVal [event] As Domain.Event) As ActionResult If Not CaptchaIsValid Then ModelState.AddModelError("recaptcha", "*") '#' Validate the ModelState and submit the data. If ModelState.IsValid Then ''# Post the form Else ''# Return View([event]) End If End Function
źródło
Rozszerzając odpowiedź Magpie, oto kod filtru akcji, którego używam w swoim projekcie.
Działa z ASP Core RC2!
public class ReCaptchaAttribute : ActionFilterAttribute { private readonly string CAPTCHA_URL = "https://www.google.com/recaptcha/api/siteverify"; private readonly string SECRET = "your_secret"; public override void OnActionExecuting(ActionExecutingContext filterContext) { try { // Get recaptcha value var captchaResponse = filterContext.HttpContext.Request.Form["g-recaptcha-response"]; using (var client = new HttpClient()) { var values = new Dictionary<string, string> { { "secret", SECRET }, { "response", captchaResponse }, { "remoteip", filterContext.HttpContext.Request.HttpContext.Connection.RemoteIpAddress.ToString() } }; var content = new FormUrlEncodedContent(values); var result = client.PostAsync(CAPTCHA_URL, content).Result; if (result.IsSuccessStatusCode) { string responseString = result.Content.ReadAsStringAsync().Result; var captchaResult = JsonConvert.DeserializeObject<CaptchaResponseViewModel>(responseString); if (!captchaResult.Success) { ((Controller)filterContext.Controller).ModelState.AddModelError("ReCaptcha", "Captcha not solved"); } } else { ((Controller)filterContext.Controller).ModelState.AddModelError("ReCaptcha", "Captcha error"); } } } catch (System.Exception) { ((Controller)filterContext.Controller).ModelState.AddModelError("ReCaptcha", "Unknown error"); } } }
I użyj go w swoim kodzie, np
[ReCaptcha] public IActionResult Authenticate() { if (!ModelState.IsValid) { return View( "Login", new ReturnUrlViewModel { ReturnUrl = Request.Query["returnurl"], IsError = true, Error = "Wrong reCAPTCHA" } ); }
źródło
Dla każdego, kto szuka, oto przyzwoity zestaw kroków. http://forums.asp.net/t/1678976.aspx/1
Nie zapomnij ręcznie dodać klucza w OnActionExecuting (), tak jak ja.
źródło