不可见的Google reCAPTCHA和Ajax表单。

15

我有一个ajax表单:

  <form id="my_form">
    <input type="text" id="field1" />
    <input type="submit" value="submit" />
  </form>

并且 JavaScript 代码:

document.getElementById("my_form").onsubmit = function(e) {
  e.preventDefault();

  var xhr = new XMLHttpRequest();
  //.............. send request to a server
在文档中,它假设表单是普通表单,而不是ajax表单。我应该如何将隐形的reCaptcha集成到我的ajax表单中?例如:
在文档中,它假设表单是普通表单,而不是 AJAX 表单。我应该如何将隐形 reCaptcha 集成到我的 AJAX 表单中?例如:
  <form id="my_form">
    <input type="text" id="field1" />
    <div class="g-recaptcha" data-sitekey="12345" data-callback="????></div>
    <input type="submit" value="submit" />
  </form>

特别是,我应该为"data-callback"处理程序指定什么?文档中又说,data-callback会提交一个表单,但是一个普通的表单,而我的是ajax。我需要"data-callback"吗?难道不应该在我的处理程序中调用recaptcha吗?如何调用?

有"render"、"getResponse"和"execute"。我应该使用哪一个?从文档中并不清楚。

2个回答

38

我认为“隐形”reCAPTCHA文档不够全面。在理解如何使用它之前,我不得不花费一些时间查看“可见”reCAPTCHA的代码示例和文档。

首先让我们谈谈reCAPTCHA API:

grecaptcha.render(htmlEl, options, inherit)是JS API渲染验证码HTML的方法。默认情况下,reCAPTCHA脚本将尝试查找任何具有class="g-recaptcha"的元素并立即渲染,但可以通过向reCAPTCHA脚本src url追加?render=explicit查询参数来覆盖此行为。当您的reCAPTCHA .g-recaptcha元素在DOM中附加到稍后时,您还可以使用此API按需渲染reCAPTCHA html。此API返回一个ID值,可传递给其他API方法,但如果不传递,则这些API会查找并引用页面上的第一个reCAPTCHA。

grecaptcha.getResponse(optional_id)返回令牌。如果令牌为空字符串,则表示用户尚未通过验证码验证,即用户尚未完成验证码挑战。

grecaptcha.execute(optional_id) api以编程方式按需触发reCAPTCHA挑战。此API仅适用于“隐形”reCAPTCHA。单击reCAPTCHA模块时,可见的reCAPTCHA挑战会被触发。

grecaptcha.reset(optional_id)将重置挑战,即每次服务器未能使用reCAPTCHA API服务器验证令牌时都必须执行此操作(因为令牌是一次性使用),但根据您的实现,您可以随时决定重置。

现在,让我们谈谈data-callback:

data-callback是一个属性,您可以通过该属性传递全局命名空间函数的名称,即某个作为window['nameOfFunction']可访问的函数。每次用户成功使用最终将传递给服务器的令牌值进行验证时,都会调用此回调。这与grecaptcha.getResponse()返回的相同令牌,因此从技术上讲,您根本不需要此函数。但是,在需要更新UI或其他内容时,它可以作为回调用于让您知道用户已经通过验证。

如果由于某种原因您不希望从窗口命名空间中访问此回调,则可以将此方法作为grecaptcha.render()中的选项对象中的callback键传递。注意:options.callback可以采用字符串值,该值等效于在HTML中传递data-callback属性,即它必须是窗口命名空间中的函数。但是,options.callback也可以采用“function”值。


现在是一些示例代码:

HTML

<script src="https://www.google.com/recaptcha/api.js?render=explicit&onload=onScriptLoad" async defer></script>

JS

window.onScriptLoad = function () {
    // this callback will be called by recaptcah/api.js once its loaded. If we used
   // render=explicit as param in script src, then we can explicitly render reCaptcha at this point

    // element to "render" invisible captcha in
    var htmlEl = document.querySelector('.g-recaptcha');

    // option to captcha
    var captchaOptions = {
      sitekey: '6Lck',
      size: 'invisible',
      // tell reCaptcha which callback to notify when user is successfully verified.
      // if this value is string, then it must be name of function accessible via window['nameOfFunc'], 
      // and passing string is equivalent to specifying data-callback='nameOfFunc', but it can be
      // reference to an actual function
      callback: window.onUserVerified
  };

    // Only for "invisible" type. if true, will read value from html-element's data-* attribute if its not passed via captchaOptions
    var inheritFromDataAttr = true;

    // now render
    recaptchaId = window.grecaptcha.render(htmlEl, captchaOptions, inheritFromDataAttr);
};

// this is assigned from "data-callback" or render()'s "options.callback"
window.onUserVerified = function (token) {
    alert('User Is verified');
    console.log('token=', token);
};


// click handler for form's submit button
function onSubmitBtnClick () {      
  var token =   window.grecaptcha.getResponse(recaptchaId);

  // if no token, mean user is not validated yet
  if (!token) {
     // trigger validation
     window.grecaptcha.execute(recaptchaId);
     return;
  }

  var xhrData = {
    'g-recaptcha-response': token
    // more ajax body/data here
  };

  // proceed with appending more ajax call data to xhrData and then rest of ajax call process
  // var xhr = new XMLHttpRequest();
  // ... ... .... ... ... 
}

好的,我想我已经把它搞对了。然而,问题——在右下角的错误定位——仍然存在。如何修复? - Kuqa
您想在表单本身中显示ReCaptcha徽标吗?为此,您可以使用data-badge属性或grecaptcha.render()中的options.badge选项。尝试options.badge =“inline”。一旦内联,您可以尝试应用自己的CSS进行配置。否则,您可以使用值bottomright将该图标移动到相反的角落。 - codneto
这个答案非常准确,做得非常好,而且非常有用。 - contrid
5
这比官方文档解释得更清楚,官方文档对渲染和执行的解释做得不好。 - cbron
我花了好几个小时尝试在我的ajax表单提交中使用不可见验证码,但是一直没有成功,但最终通过您的答案找到了解决方法。 - Fergal Andrews
运行完美。不过后端方面有什么信息吗? - EPurpl3

-1

您可以使用jQuery轻松验证Google reCAPTCHA

<?php 
$remoteip = $_SERVER['REMOTE_ADDR'];
?>
<script type="text/javascript">
    function reloadRecaptcha() {
        var publicKey = "your_public_key";
        var div = "recap";
        Recaptcha.create(publicKey,div,{theme: "white"});
        return false;
    }
    function validate() {

        var challenge = Recaptcha.get_challenge();
        var response = Recaptcha.get_response();
        var remoteip = "<?php echo $remoteip; ?>";
        $.ajax({
          type: "POST",
          url: "validateRecaptcha.php",
          async: false,
          data: {
            remoteip: remoteip,
            challenge: challenge,
            response: response
          },
          success: function(resp) {
                if(resp == "true") {
                    document.getElementById("message").innerHTML = "Perfect!";
                }
                else {
                    document.getElementById("message").innerHTML = "Incorrect Recaptcha! Please try again!";
                    reloadRecaptcha();
                }
          }
        });
        return false;
    }


有趣的代码,但缺少信息... Recaptcha 的声明,var div = "recap"; 是什么? - Fenix Aoras

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