不可见的 google Recaptcha 和 ajax 表单

Posted

技术标签:

【中文标题】不可见的 google Recaptcha 和 ajax 表单【英文标题】:Invisible google Recaptcha and ajax form 【发布时间】:2017-08-09 03:30:54 【问题描述】:

我有一个 ajax 表单:

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

还有js代码:

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

  var xhr = new XMLHttpRequest();
  //.............. send request to a server

在文档中,它假定表单是普通表单,而不是 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 提交了一个表单,但是一个普通的表单,而我的是 ajax。我需要“数据回调”吗?我不应该在我的处理程序中调用 recaptcha 吗?怎么样?

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

【问题讨论】:

【参考方案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"; 是什么【参考方案2】:

我同意“不可见的”recaptcha 文档不够全面。在了解如何使用它之前,我不得不花一些时间通过代码示例和“可见”recaptcha 的文档进行挖掘。

先说一下recaptcha API:

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

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

grecaptcha.execute(optional_id) api 以编程方式按需触发recaptcha 质询。此 api 仅适用于“不可见”的 recaptcha。当用户点击recaptcha模块时,会触发可见的recaptcha挑战。

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

现在,让我们谈谈数据回调:

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

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


现在是一些示例代码:

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();
  // ... ... .... ... ... 

【讨论】:

好的。我想我已经开始工作了。然而,问题 - 右下角的错误定位 - 仍然存在。如何解决? 您想在表单中显示 ReCaptcha 徽标吗?为此,您可以在grecaptcha.render() 中使用data-badge 属性或options.badge 选项。试试options.badge = "inline"。内联后,您可以尝试应用自己的 CSS 来配置它。否则,您可以使用值 bottomright 将该图标移动到对角 这个答案很到位,做得很好,非常有用。 这比官方文档解释得更好,他们在解释渲染与执行方面做得不好。 我花了几个小时试图让不可见的验证码与我的 ajax 表单提交一起工作,但没有运气,但由于你的回答终于弄明白了。

以上是关于不可见的 google Recaptcha 和 ajax 表单的主要内容,如果未能解决你的问题,请参考以下文章

Google reCAPTCHA 错误:提供的云项目编号不拥有给定的 reCAPTCHA 密钥

Google reCaptcha 2 TypeError:调用 grecaptcha.reset 后 a 为空

为啥 Google ReCaptcha 不阻止提交表单?

Google reCaptcha 重置不起作用

Google reCaptcha v3 与 google reCaptcha Enterprise

谷歌人机验证 (reCAPTCHA) 显示不出来?