Invisible ReCaptcha with jQuery ajax

2019-04-22 09:37发布

问题:

I am trying to implement the newest ReCaptcha (aka "invisible" ReCaptcha) within an form using jQuery and an "ajax" request.
ReCaptcha documentation: https://developers.google.com/recaptcha/docs/invisible

My form:

<form id="myForm" >
    <input type="email" name="email" /><br />
    <input type="password" name="password" /><br/>
    <!--<input type="submit" value="log in" />-->
    <button class="g-recaptcha" data-sitekey="6LdK..." data-callback="onSubmit">log in</button>
</form>
<div id="status"></div>

My javascript (jQuery):

<script>

    function onSubmit(token){
        document.getElementById("myForm").submit();
    }

    $(document).ready(function(){

        $("#myForm").submit(function(event){
            event.preventDefault();
            var datas = $("#myForm").serialize();
            $.ajax({
                type: "POST",
                url: "test.php",
                data: datas,
                dataType: "json",
                    beforeSend: function(){
                        $("#status").html("logging in...");
                    },
                    success: function(response){
                        $("#status").html(response.text);
                        if(response.type=="success"){
                            window.location.replace("/myaccount");
                        }
                    },
                    error: function(){
                        $("#status").html("Failed.");
                    }
            });
        });

    });
</script>

ReCaptcha requires to set a "data-callback", which I am not sure how to bind with my already existing ".submit(function(event)" function.
My "onSubmit()" trick did not work, it ignores the "ajax" and refreshes the page.

How do I send the "g-recaptcha-response" value within my "datas" variable to POST it to test.php?

回答1:

So here is how I solved it after digging further in Invisible reCAPTCHA's doc, and learning a bit of jQuery obviously since I was not very familiar with JS (cool stuff):

My head tag with the javascript (and a bit of css to remove the ugly Google badge):

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit&hl=fr" async defer></script>

<style>
    .grecaptcha-badge{
        display:none;
    }
</style>

<script>
    var onloadCallback = function(){
        grecaptcha.render("emplacementRecaptcha",{
            "sitekey": "YOUR_RECAPTCHA_SITEKEY_HERE",
            "badge": "inline",
            "type": "image",
            "size": "invisible",
            "callback": onSubmit
        });
    };
    var onSubmit = function(token){
        var userEmail = $("#userEmail").val();
        var userPassword = $("#userPassword").val();
        var userTfaOtp = $("#userTfaOtp").val();
        $.ajax({
            type: "POST",
            url: location.href,
            data:{
                    userEmail: userEmail,
                    userPassword: userPassword,
                    userTfaOtp: userTfaOtp,
                    userJetonRecaptcha: token
                },
            dataType: "json",
                beforeSend: function(){
                    $("#statutConnexion").html("Traitement de votre requête d'authentification en cours...");
                },
                success: function(response){
                    $("#statutConnexion").html(response.Message);
                    if(response.Victoire){
                        $("#formulaireConnexion").slideUp();
                        window.location.replace("/compte");
                    }
                    else{
                        grecaptcha.reset();
                    }
                },
                error: function(){
                    $("#statutConnexion").html("La communication avec le système d'authentification n'a pas pu être établie. Veuillez réessayer.");
                    grecaptcha.reset();
                }
        });
    };
    function validate(event){
        event.preventDefault();
        $("#statutConnexion").html("Validation de votre épreuve CAPTCHA en cours...");
        grecaptcha.execute();
    }
    function onload(){
        var element = document.getElementById("boutonConnexion");
        element.onclick = validate;
    }
</script>

HTML:

<div id="formulaireConnexion">
    <input type="email" name="userEmail" id="userEmail" placeholder="Courriel" title="Courriel" required="required" /><br />
    <input type="password" name="userPassword" id="userPassword" placeholder="Mot de passe" title="Mot de passe" required="required" /><br/>
    <input type="text" name="userTfaOtp" id="userTfaOtp" placeholder="Double authentification (optionnelle)" autocomplete="off" pattern="[0-9]{6}" title="Six caractères numériques" maxlength="6" /><br />
    <div id="emplacementRecaptcha"></div>
    <button id="boutonConnexion">Connexion</button>
</div>
<div id="statutConnexion"></div>
<script>onload();</script>

Let me know if you need the whole PHP as well since it's out of the scope of this question. You will probably need to change "url: location.href," within the JS above since in my case the script rendering the HTML form and the JS and dealing with the POST vars is the same (not great, testing purpose). Basically I just verify the POST vars then finally return a json like:

$jsonVictoire = true; // boolean
$jsonMessage = 'anything you want to tell your visitor'; // string

$return = 
    json_encode(
        array(
            'Victoire'=>$jsonVictoire,
            'Message'=>$jsonMessage
        )
    );
die($return);


回答2:

<script defer>              
function onSubmit(token) {                      
    var f = $("#myForm");

    $.ajax({
        type: "POST",
        url: "test.php",
        data: f.serialize(),
        dataType: "json",
        beforeSend: function(){
            $("#status").html("logging in...");
        },
        success: function(response){
            $("#status").html(response.text);
            if(response.type=="success"){
                window.location.replace("/myaccount");
            } else {
                $("#status").html("Captcha failed.");
            }
        },
        error: function(){
            $("#status").html("Failed.");
        }       
    });
}
</script>

In test.php you need to verify captcha on server side:

<?php
if(isset($_POST['g-recaptcha-response'])) {
    $result = json_decode(file_get_contents('https://www.google.com/recaptcha/api/siteverify?secret=[YOUR_SECRET_KEY]&response=$_POST["g-recaptcha-response"]&remoteip=$_SERVER["REMOTE_ADDR"]'), TRUE);

    if($result['success'] == 1) {
        // Captcha ok
    } else {
        // Captcha failed
    }
}
?>