Wie implementiere ich reCaptcha für ASP.NET MVC? [geschlossen]


80

Wie implementiere ich reCaptcha in ASP.NET MVC und C #?


Wenn Sie nach der neuesten Lösung von Combined Google reCAPTCHA v2 und v3 in ASP.NET Web Forms suchen
Leo

Antworten:


82

Es gibt einige gute Beispiele:

Dies wurde auch bereits in dieser Frage zum Stapelüberlauf behandelt .

NuGet Google reCAPTCHA V2 für MVC 4 und 5


Danke für die schnelle Antwort. Ich habe eine Frage, wer hat erstellt Recaptcha.dll? Google-Team?
xport

4
Ich glaube, ReCaptcha wurde von einem Professor an der Carnegie Mellon University entwickelt .
George Stocker

1
Der dritte ( dotnetcurry.com/ShowArticle.aspx?ID=611 ) hat für mich großartig funktioniert.
Seldary

Ich benutze den Code von Dirik Whittaker. Auf Microsoft.Web.Helpers wird verwiesen, aber in dieser Zeile wird der Namespace-Name "Recaptcha" nicht gefunden: var captchaValidtor = new Recaptcha.RecaptchaValidator
M3NTA7

@ M3NTA7 Vielleicht möchten Sie eine Frage stellen, die etwas tiefer geht als dieser Kommentar.
George Stocker

32

Ich habe einem Projekt, an dem ich gerade arbeite, reCaptcha hinzugefügt. Ich brauchte es, um die AJAX-API zu verwenden, da das reCaptcha-Element dynamisch in die Seite geladen wurde. Ich konnte keine vorhandenen Steuerelemente finden und die API ist einfach, daher habe ich meine eigenen erstellt.

Ich werde meinen Code hier posten, falls jemand ihn nützlich findet.

1: Fügen Sie das Skript-Tag zu den Kopfzeilen der Masterseite hinzu

<script type="text/javascript" src="http://www.google.com/recaptcha/api/js/recaptcha_ajax.js"></script>

2: Fügen Sie Ihre Schlüssel zur web.config hinzu

<appSettings>
    <add key="ReCaptcha.PrivateKey" value="[key here]" />
    <add key="ReCaptcha.PublicKey" value="[key here]" />
</appSettings>

3: Erstellen Sie die Erweiterungen Action Attribute und 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: Fügen Sie das Captcha Ihrer Ansicht hinzu

@using (Html.BeginForm("MyAction", "MyController"))
{
   @Html.TextBox("EmailAddress", Model.EmailAddress)
   @Html.GenerateCaptcha(Theme.White)
   <input type="submit" value="Submit" />
}

5: Fügen Sie das Attribut Ihrer Aktion hinzu

[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: Beachten Sie, dass Sie das Captcha nach jedem Beitrag neu laden müssen, auch wenn es gültig und ein anderer Teil des Formulars ungültig war. VerwendenRecaptcha.reload();


Ist es mit diesem Code möglich, ReCaptcha erst nach 5 fehlgeschlagenen Anmeldungen mit Anmerkungen zu versehen?
Rob

2
Wenn Sie diese Lösung implementieren, müssen Sie berücksichtigen, dass die neue API-URL lautet: google.com/recaptcha/api/siteverify ( Quelle )
Axel Prieto

13

Einfache und vollständige Lösung für mich. Unterstützt ASP.NET MVC 4 und 5 (Unterstützt ASP.NET 4.0, 4.5 und 4.5.1)

Schritt 1: Installieren Sie das NuGet-Paket mit " Install-Package reCAPTCH.MVC ".

Schritt 2: Fügen Sie Ihren öffentlichen und privaten Schlüssel zu Ihrer Datei web.config im Abschnitt appsettings hinzu

<appSettings>
    <add key="ReCaptchaPrivateKey" value=" -- PRIVATE_KEY -- " />
    <add key="ReCaptchaPublicKey" value=" -- PUBLIC KEY -- " />
</appSettings>  

Sie können unter https://www.google.com/recaptcha/intro/index.html ein API-Schlüsselpaar für Ihre Site erstellen und oben auf der Seite auf Get reCAPTCHA klicken

Schritt 3: Ändern Sie Ihr Formular so, dass es reCaptcha enthält

@using reCAPTCHA.MVC
@using (Html.BeginForm())
{
    @Html.Recaptcha()
    @Html.ValidationMessage("ReCaptcha")
    <input type="submit" value="Register" />
}

Schritt 4 : Implementieren Sie die Controller-Aktion, die die Formularübermittlung und die Captcha-Validierung übernimmt

[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
    {
    }
}

ODER

public ActionResult MyAction(myVM model, bool captchaValid)
{
    if (captchaValid) //manually check for captchaValid 
    {
    }
}

Leider ist es aufgrund nicht möglich, es in zwei verschiedenen Formen auf derselben Seite zu verwenden Uncaught Error: ReCAPTCHA placeholder element must be empty.
Alisson

1
Da reCaptcha die web.config für die Schlüssel verwendet, müssen Sie diese nicht angeben PrivateKey = "your private reCaptcha Google Key". Dies ist viel einfacher, wenn Sie verschiedene Schlüssel für verschiedene Umgebungen haben
Red

12

Eine asynchrone Version für MVC 5 (dh Vermeiden von ActionFilterAttribute, das erst mit MVC 6 asynchron ist) und 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>

Das hat bei mir funktioniert! ... MVC v5, recaptcha v2 ~ 2018
MTAdmin

8

Schritt 1: Client-Site-Integration

Fügen Sie dieses Snippet vor dem schließenden </head>Tag in Ihre HTML-Vorlage ein:

<script src='https://www.google.com/recaptcha/api.js'></script>

Fügen Sie dieses Snippet am Ende der Stelle ein, an der <form>das reCAPTCHA-Widget angezeigt werden soll:

<div class="g-recaptcha" data-sitekey="your-site-key"></div>

Schritt 2: Server-Site-Integration

Wenn Ihre Benutzer das Formular senden, in das Sie reCAPTCHA integriert haben, erhalten Sie als Teil der Nutzlast eine Zeichenfolge mit dem Namen "g-recaptcha-response". Um zu überprüfen, ob Google diesen Nutzer überprüft hat, senden Sie eine POST-Anfrage mit folgenden Parametern:

URL: https://www.google.com/recaptcha/api/siteverify

Geheimnis: Ihr geheimer Schlüssel

Antwort: Der Wert von 'g-recaptcha-Antwort'.

Jetzt in Aktion Ihrer MVC-App:

// 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 :)
    }

6

Ich habe ReCaptcha folgendermaßen erfolgreich implementiert.
Hinweis: Dies ist in VB, kann aber leicht konvertiert werden

1] Holen Sie sich zuerst eine Kopie der reCaptcha-Bibliothek

2] Erstellen Sie anschließend einen benutzerdefinierten 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] Von hier aus benötigen Sie einen wiederverwendbaren serverseitigen Validator

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

über dieser Zeile ist wiederverwendbarer ** EINMALIGER ** Code


Unter dieser Zeile sehen Sie, wie einfach es ist, reCaptcha immer wieder zu implementieren

Jetzt, da Sie Ihren wiederverwendbaren Code haben, müssen Sie nur noch das Captcha zu Ihrer Ansicht hinzufügen.

<%: Html.reCaptcha %>

Und wenn Sie das Formular an Ihren Controller senden ...

    ''# 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

Hinweis: Dies ist in VB, kann aber leicht in C # konvertiert werden
Chase Florell

1
Vielen Dank für die Ausarbeitung der Lösung. Es ist eine sehr detaillierte Antwort. Ich liebe es.
xport

1
Laut Joels jüngstem Blog möchten die Entwickler von StackOverflow, dass dies ein Wiki-Repository ist, anstatt nur Benutzer auf andere Websites umzuleiten. Wenn Sie auf eine Website gesendet werden, wird Ihre Frage möglicherweise heute beantwortet, das Problem eines anderen wird jedoch nicht gelöst, wenn diese externe Seite im nächsten Jahr nicht mehr angezeigt wird. Das Posten der richtigen Antwort hier hilft auch zukünftigen Suchenden. Ich glaube, das ist der richtige Weg, um eine Frage zu beantworten.
Chase Florell

Sieht fast ähnlich aus wie devlicio.us/blogs/derik_whittaker/archive/2008/12/02/… mit Ausnahme des Sprachunterschieds.
Google Mail-Benutzer

2

Als Erweiterung der Antwort von Magpie finden Sie hier den Code für den Aktionsfilter, den ich in meinem Projekt verwende.

Es funktioniert mit 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");
        }
    }
}

Und verwenden Sie es in Ihrem Code wie

[ReCaptcha]
    public IActionResult Authenticate()
    {

        if (!ModelState.IsValid)
        {
            return View(
                "Login",
                new ReturnUrlViewModel
                {
                    ReturnUrl = Request.Query["returnurl"],
                    IsError = true,
                    Error = "Wrong reCAPTCHA"
                }
            );
        }

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.