使用jQuery验证插件的新reCaptcha

54

我搜索了一下,但不知道如何在表单提交之前验证新的reCaptcha,同时使用jQuery验证插件的验证函数。

我的意图:

    $.validator.addMethod('reCaptchaMethod', function (value, element, param) {
            if (grecaptcha.getResponse() == ''){
                return false;
            } else {
                // I would like also to check server side if the recaptcha response is good
                return true
            }
        }, 'You must complete the antispam verification');


    $("#form").validate({
            rules: {
                name: {
                    required: true,
                    minlength: 2
                },
                email: {
                    required: true,
                    email: true
                },
                reCaptcha: {
                    reCaptchaMethod: true   
                }
            },
            messages: {
                name: "Please fill your name",
                email: "Please use a valid email address"
            },
            submitHandler : function () {
                        $.ajax({
                            type : "POST",
                            url : "sendmail.php",
                            data : $('#form').serialize(),
                            success : function (data) {
                                $('#message').html(data);
                            }
                        });
                    }


        });

简而言之:我想通过远程方法在服务器端检查用户是否已经通过了recaptcha验证,然后再提交表单,同时进行其他验证规则。我可以在提交后(在sendmail.php上)检查recaptcha,但是最好能够在其他字段验证的同时获得recaptcha验证响应。
主要原因是为了更好的用户体验,一次性检查所有字段。
我已经成功实现了这一点,将检查移动到submitHandler中。
            submitHandler : function () {
                  if (grecaptcha.getResponse() == ''){
                      // if error I post a message in a div
                      $( '#reCaptchaError' ).html( '<p>Please verify youare human</p>' );

                  } else {

                        $.ajax({
                            type : "POST",
                            url : "sendmail.php",
                            data : $('#form').serialize(),
                            success : function (data) {
                                $('#message').html(data);
                            }
                        });
                    }

             }

但我不喜欢这种方法,原因有两个:

  1. 它只是检查reCAPTCHA是否已填写,而不是有效的。
  2. 用户感觉像是一个2步验证。

在这个答案中,他们说可以通过回调渲染reCAPTCHA,以指定在成功的验证码响应上调用函数。

我尝试实现了这个方法,但我无法在validate()函数的规则中使用此解决方案。


从客户端验证reCAPTCHA响应是否安全?您如何包含secret_key?相对于服务器端验证,有什么优势? - user557657
4个回答

110

我知道这个问题有点过时了,但是我遇到了同样的问题,现在找到了解决方法。 你可以在reCaptcha div旁边添加一个隐藏字段来实现,例如:

<div class="g-recaptcha" data-sitekey="{YOUR-SITE-KEY-HERE}"></div>
<input type="hidden" class="hiddenRecaptcha required" name="hiddenRecaptcha" id="hiddenRecaptcha">

然后在你的JavaScript中:

$("#form").validate({
        ignore: ".ignore",
        rules: {
            name: {
                required: true,
                minlength: 2
            },
            email: {
                required: true,
                email: true
            },
            hiddenRecaptcha: {
                required: function () {
                    if (grecaptcha.getResponse() == '') {
                        return true;
                    } else {
                        return false;
                    }
                }
            }
        },(...rest of your code)

请注意,在您的代码中必须包含ignore:".ignore",因为jquery.validate默认忽略隐藏字段,不对其进行验证。

如果您想要在reCaptcha验证时移除错误消息,请向reCaptcha元素添加data-callback属性。

<div class="g-recaptcha" data-sitekey="{YOUR-SITE-KEY-HERE}" data-callback="recaptchaCallback"></div>

然后在你的js文件中添加以下内容

function recaptchaCallback() {
  $('#hiddenRecaptcha').valid();
};

1
只是要补充一点,确保不要将recaptchaCallback()放在文档准备好的函数内。这样它就无法被data-callback事件访问到了。 - Petar-Krešimir
1
当无效时,所需规则的函数是否应返回true?这样可以吗? - Phoenix_uy
1
@Phoenix_uy 很抱歉回复晚了。是的,如果验证码答案无效,您必须声明隐藏字段是必需的,以显示错误。 - FabioG
嗨,最近我看到了错误ReCAPTCHA无法找到用户提供的函数:recaptchaCallback。 我认为这是由于Google延迟加载其脚本引起的。 有人知道如何解决吗? 结果是表格不再发布。 请帮忙! - chocolata
1
用户将如何看到验证错误消息?我已经让验证函数运行,但UI界面没有任何变化。 - Jeff
显示剩余4条评论

17

您还可以在submitHandler中防止表单提交

$("#loginForm").validate({
rules: {
    username: {
        required: true,
        minlength: 6
    },
    password: {
        required: true,
    },
},
submitHandler: function(form) {
    if (grecaptcha.getResponse()) {
        form.submit();
    } else {
        alert('Please confirm captcha to proceed')
    }
}
});

1
嗨Ranjith,我正在使用相同的代码,但是我使用ajax代码而不是form.submit();。我该如何使用它? - Naren Verma
@NarenVerma 在 form.submit() 的位置上放置你的 ajax 代码。 - Ranjith Singhu Ganapathy

5
我发现你的解决方案很有趣(@FabioG)。

但是,我对它进行了一些修改以便自己使用,我愿意分享代码让其他人使用。

我正在开发一个交互式表单,可以在完成步骤时进行验证。

它被用于订购食物。因此,该表单需要验证和激活注册按钮,并且使用了最新的reCaptcha(2016年5月12日)。

此外,这个代码处理了过期的reCaptcha,通过ajax进行服务器端验证(虽然没有包含 - 如果有人需要,请在我的答案下评论,我会相应地编辑它)。

让我们开始吧。

HTML代码:

<form id="registerForm" method="get" action="">
<fieldset class="step-1">
<h4>Step One:</h4>
<span class="clock">Register under one minute!</span>
<label for="email-register" class="label">E-mail*</label>
<input id="email-register" name="email-register" type="email" value="" autocomplete="off"/>

<label for="password-register" class="label">Password*</label>
<input id="password-register" name="password-register" type="password" value="" autocomplete="off"/>

<div class="g-recaptcha" data-sitekey="6LeS4O8SAAAAALWqAVWnlcB6TDeIjDDAqoWuoyo9" data-callback="recaptchaCallback" data-expired-callback="recaptchaExpired" style="margin-top: 3rem;"></div>
<input id="hidden-grecaptcha" name="hidden-grecaptcha" type="text" style="opacity: 0; position: absolute; top: 0; left: 0; height: 1px; width: 1px;"/>
</div>
</fieldset>
<fieldset class="step-2">
<h4>Step two:</h4>
<span class="notice">All fields with a sign are required!*</span>
<label for="first-name" class="label">First Name*</label>
<input name="first-name" id="first-name" type="text" value="" />

<label for="last-name" class="label">Last Name*</label>
<input name="last-name" id="last-name" type="text" value="" />

<label for="address" class="label">Address*</label> 
<input name="address" id="address" type="text" value=""/>

<label for="entrance" class="label">Entrance</label>    
<input name="entrance" id="entrance" type="text" value=""/>

<label for="apartment-number" class="label">Apartment #</label>
<input name="apartment-number" id="apartment-number" type="text" value="" />

<label for="inter-phone" class="label">Interphone</label>           
<input name="inter-phone" id="inter-phone" type="text" value=""/>

<label for="telephone" class="label">Mobile Number*</label>
<input name="telephone" id="telephone" type="text" value="" />

<label for="special-instructions" class="label">Special Instructions</label>    
<textarea name="special-instructions" id="special-instructions"></textarea>
<div>
</fieldset>
<button class="button-register" disabled>Register</button>
</form>

所以,正如您所看到的,提交按钮(“ .button-register”)最初是< strong>禁用的。
只有填写< strong>强制性 (*)字段才能启用它。
请记住,我没有包含任何CSS。表格最少,仅供教育目的。
与@FabioG不同的几件事情是:
没有必要隐藏元素或使用“.ignore”。我用内联CSS隐藏了它。
成功reCaptcha和过期reCaptcha都有< strong>响应回调。
因此,如果您的reCaptcha在填写表单时过期,它将使其< strong>无效,并且按钮将再次< strong>禁用。
此外,该表单使用输入字段(隐藏输入字段)将信息传递给AJAX(稍后为PHP)并在服务器端进行验证< em>(这是潜在的安全风险,我在文本末尾更详细地介绍了它)。 让我们继续JavaScript / jQuery。
function debounce(func, wait, immediate) {
    var timeout;
    return function() {
        var context = this, args = arguments;
        var later = function() {
            timeout = null;
            if (!immediate) func.apply(context, args);
        };
        var callNow = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        if (callNow) func.apply(context, args);
    };
};
function recaptchaCallback() {
    var response = grecaptcha.getResponse(),
        $button = jQuery(".button-register");
    jQuery("#hidden-grecaptcha").val(response);
    console.log(jQuery("#registerForm").valid());
    if (jQuery("#registerForm").valid()) {
        $button.attr("disabled", false);
    }
    else {
        $button.attr("disabled", "disabled");
    }
}

function recaptchaExpired() {
    var $button = jQuery(".button-register");
    jQuery("#hidden-grecaptcha").val("");
    var $button = jQuery(".button-register");
    if (jQuery("#registerForm").valid()) {
        $button.attr("disabled", false);
    }
    else {
        $button.attr("disabled", "disabled");
    }
}
function submitRegister() {
  //ajax stuff
}
(function ($, root, undefined) {
    $(function () {
        'use strict';
        jQuery("#registerForm").find("input").on("keyup", debounce(function() {
          var $button = jQuery(".button-register");
          if (jQuery("#registerForm").valid()) {
            $button.attr("disabled", false);
          }
          else {
            $button.attr("disabled", "disabled");
          }
        }, 1000));
        jQuery("#registerForm").validate({
          rules: {
            "email-register": {
              required: true,
              email: true
            },
            "password-register": {
              required: true,
              minlength: "6"
            },
            "first-name": "required",
            "last-name": "required",
            address: "required",
            telephone: "required",
            "hidden-grecaptcha": {
              required: true,
              minlength: "255"
            }
          },
          messages: {
            "email-register": "Enter valid e-mail address",
            "password-register": {
              required: "Enter valid password",
              minlength: "Password must be bigger then 6 chars!"
            },
            "first-name": "Required!",
            "last-name": "Required!",
            address: "Required!",
            telephone: "Required!"
          },
          submitHandler: submitRegister
        });
    }); 
})(jQuery, this);

如您所见,这里有几个函数:recaptchaCallback()recaptchaExpired()
通过数据属性data-callback嵌入的recaptchaCallback() 函数,使用grecaptcha.getResponse() 来查看reCaptcha是否已验证,如果是,则将令牌输入隐藏的输入字段,并通过jQuery("#registerForm).validate(); 请求重新验证。
然而,如果reCaptcha在此期间过期,它将使用“data-expired-callback”中分配的函数,从输入字段中删除令牌并再次请求重新验证,但因为该字段为空,验证将失败。这是通过recaptchaExpired()函数实现的。
在代码的后面,可以看到我们添加了一个jQuery keyup函数,以检查重新验证,并查看用户是否已将所需信息传递给输入字段。如果信息和字段成功验证,则keyup函数将启用注册按钮。
此外,我使用了一个去抖脚本(感谢David Walsh)在keyup上。这样就不会导致浏览器卡顿。因为需要输入很多内容。
但是,请记住,如果用户决定规避reCaptcha,他总是可以将“255”个字符长的字符串输入到输入字段中。但是,我更进一步,做了一个AJAX验证服务器端来确认reCaptcha。虽然,我没有包含它在答案中。
我认为这段代码对之前的答案有一点改进。如果您有任何问题或需要AJAX / PHP代码,请随时评论。我会尽快提供。
这里也有Codepen:reCaptcha with jQuery.validation 您可以在此处找到有关reCatpcha数据属性和函数的所有信息:reCaptcha API 希望对某人有所帮助!
问候,

这个代码可以运行,但对用户来说有点不方便,因为你的 .on("keyup" 调用会在你填写完表单之前提示验证错误。如果在点击“注册”按钮后表单无效时再显示提示信息会更好。 - MeSo2

2

今天我遇到了这个问题,最终采用了以下解决方案:

<form onsubmit="return $(this).valid() && grecaptcha.getResponse() != ''">

这似乎是最简单的方法。有人可能会抱怨这样内联js,但我认为没问题。


2
问题是我想将验证码验证与jQuery .Validate()函数集成,这样我就可以向用户呈现填写字段的单个错误列表。抱歉,但我不明白如何使用您的解决方案来实现这一点? - bluantinoo
你可以通过调用一个函数来实现它。例如:<form onsubmit="return validateForm()">,然后在 script 标签中,你可以调用这个函数并编写你的代码:function validateForm(){ //在这里编写代码 } - Rinku Choudhary
它对我很有帮助,感谢@pguardiario提供这个漂亮的解决方案。 - Rinku Choudhary

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接