Comment mettre en œuvre reCaptcha pour ASP.NET MVC? [fermé]

comment mettre en œuvre reCaptcha dans ASP.NET MVC et C#?

63
demandé sur George Stocker 2011-01-06 05:00:51

8 réponses

il y a quelques grands exemples:

Cette question a déjà été abordée dans la section de la question .

NuGet Google reCAPTCHA V2 for MVC 4 and 5

73
répondu George Stocker 2017-05-23 12:02:50

j'ai ajouté reCaptcha à un projet sur lequel je travaille actuellement. J'en avais besoin pour utiliser L'API AJAX car l'élément reCaptcha était chargé dynamiquement dans la page. Je n'ai trouvé aucun contrôle existant et L'API est simple donc j'ai créé le mien.

je poste mon code ici au cas où quelqu'un le trouve utile.

1: Ajouter la balise script aux en-têtes de la page principale

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

2: Ajoutez vos clés au web.config

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

3: Créer L'attribut Action et les extensions 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: Ajouter le captcha à votre vue

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

5: ajouter l'attribut à votre action

[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: Note vous aurez besoin de recharger le captcha après chaque message même si elle était valide et qu'une autre partie du formulaire était invalide. Use Recaptcha.reload();

28
répondu Magpie 2015-07-30 13:30:01

Solution Simple et Complète "151960920 de travail" pour moi. Supports ASP.NET MVC 4 et 5 (Supports ASP.NET 4.0, 4.5 et 4.5.1)

Étape 1: Install Package NuGet par " Install-Package reCAPTCH.MVC "

Étape 2: Ajoutez vos clés publiques et privées à votre site web.fichier de configuration dans la section appsettings

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

vous pouvez créer un Paire de clés API pour votre site à https://www.google.com/recaptcha/intro/index.html et cliquez sur Get reCAPTCHA au début de la page

Étape 3: modifier votre formulaire pour inclure reCaptcha

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

Étape 4 : implémenter l'Action du contrôleur qui traitera la soumission du formulaire et la validation 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
    {
    }
}

ou

public ActionResult MyAction(myVM model, bool captchaValid)
{
    if (captchaValid) //manually check for captchaValid 
    {
    }
}
11
répondu Moji 2016-11-15 12:08:36

J'ai implémenté avec succès ReCaptcha de la manière suivante.

note: Ceci est en VB, mais peut facilement être converti

1] prenez D'abord une copie de la reCaptcha library

2] puis construire un personnalisé 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] D'ici vous avez besoin d'un re-server usable side 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

au-dessus de cette ligne est réutilisable * * une fois * * code


au-dessous de cette ligne est combien il est facile d'implémenter reCaptcha plus de

Maintenant que vous avez votre code réutilisable... tout ce que vous devez faire est d'ajouter le captcha à votre Vue.

<%: Html.reCaptcha %>

Et quand vous postez le formulaire à votre contrôleur...

    ''# 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
6
répondu Chase Florell 2011-01-12 11:44:35

Étape 1: intégration du Site Client

collez cet extrait avant la fermeture de la balise </head> sur votre modèle HTML:

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

collez cet extrait à la fin du <form> où vous voulez que le widget reCAPTCHA apparaisse:

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

Étape 2: intégration du Site Serveur

lorsque vos utilisateurs soumettent le formulaire où vous avez intégré reCAPTCHA, vous obtiendrez comme partie de la charge utile a chaîne avec le nom "g-recaptcha-réponse". Afin de vérifier si Google a vérifié cet utilisateur, envoyez une demande par courrier électronique avec ces paramètres:

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

secret: votre clé secrète

réponse : La valeur de "g-recaptcha-réponse".

maintenant en action de votre application 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 :)
    }
6
répondu Thinh Vu 2015-12-06 20:52:35

une version asynchrone pour MVC 5 (c.-à-d. éviter ActionFilterAttribute, qui n'est pas asynchrone avant MVC 6) et 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>
4
répondu Brent 2017-01-15 18:39:45

pour quiconque regarde ailleurs, voici un bon ensemble de pas. http://forums.asp.net/t/1678976.aspx/1

n'oubliez pas d'ajouter manuellement votre clé dans OnActionExecuting() comme je l'ai fait.

1
répondu Pat 2011-10-27 22:44:34

en prolongeant la réponse de Magpie, voici le code pour le filtre d'action que j'utilise dans mon projet.

Il travaille avec 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");
        }
    }
}

et utilisez-le dans votre code comme

[ReCaptcha]
    public IActionResult Authenticate()
    {

        if (!ModelState.IsValid)
        {
            return View(
                "Login",
                new ReturnUrlViewModel
                {
                    ReturnUrl = Request.Query["returnurl"],
                    IsError = true,
                    Error = "Wrong reCAPTCHA"
                }
            );
        }
1
répondu Dmytro Bogatov 2016-06-13 11:35:55