如何在单个页面上显示多个reCAPTCHA?

119

我在单一页上有两个表格。其中一个表格一直显示Recaptcha验证码,而另一个表格只有在特定事件发生后才会显示Recaptcha验证码,比如最大登录尝试次数超限。因此,在同一页上需要出现两个Recaptcha验证码的情况。这种情况可行吗?虽然我知道可能可以用一个Recaptcha验证码来解决,但是,基于我的布局方式,我更喜欢使用两个。谢谢。

更新:好吧,我想这可能不可能。有人能推荐与reCaptcha并排使用的其他验证码库吗?我真的很想在同一页上有两个验证码。

更新2:如果我将每个表格放在一个iframe中,这样做是否可行呢?


你不能只是简单地显示同一个两次吗? - Tyler Carter
1
我尝试过了,当我尝试复制验证码代码时,它只会显示第一个出现的验证码。 - oym
1
任何遇到新的reCAPTCHA API的人,可以通过在文档https://developers.google.com/recaptcha/docs/display#recaptcha_methods中描述的显式加载方法来实现。该文档提供了示例。 - El Yobo
3
与使用iframe相比,像Hüseyin Yağlı的回答中推荐的使用JavaScript是解决该问题的更好方式。大多数浏览器应该支持JavaScript,而默认的reCAPTCHA也已经使用了JavaScript。但我不知道如果没有JavaScript支持,需要做些什么才能解决这个问题。 - Edward
17个回答

224

使用当前版本的Recaptcha (reCAPTCHA API version 2.0),您可以在同一个页面上使用多个Recaptchas。

没有必要克隆Recaptcha或尝试解决问题。您只需为Recaptchas放置多个<div>元素,并在其中显式地呈现Recaptchas即可。

借助Google Recaptcha API,这很容易。以下是示例HTML代码:

<form>
    <h1>Form 1</h1>
    <div><input type="text" name="field1" placeholder="field1"></div>
    <div><input type="text" name="field2" placeholder="field2"></div>
    <div id="RecaptchaField1"></div>
    <div><input type="submit"></div>
</form>

<form>
    <h1>Form 2</h1>
    <div><input type="text" name="field3" placeholder="field3"></div>
    <div><input type="text" name="field4" placeholder="field4"></div>
    <div id="RecaptchaField2"></div>
    <div><input type="submit"></div>
</form>

在您的JavaScript代码中,您必须为Recaptcha定义一个回调函数:

<script type="text/javascript">
    var CaptchaCallback = function() {
        grecaptcha.render('RecaptchaField1', {'sitekey' : '6Lc_your_site_key'});
        grecaptcha.render('RecaptchaField2', {'sitekey' : '6Lc_your_site_key'});
    };
</script>

完成后,你的reCAPTCHA脚本URL应该像这样:

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

或者,您可以为您的Recaptcha字段提供一个类名,使用您的类选择器循环这些元素并调用.render(),而不是给它们分配ID。


2
@IvanJuarez 这是一个很好的问题,可以作为一个新问题提出来。 - Huseyin Yagli
4
若您想在多个实例中使用grecaptcha.getResponse(),只需将每个呈现引用为0、1、2等即可。例如,第一个实例将被引用为grecaptcha.getResponse(0)。 - Gene Kelly
2
节省我的时间,这是完美的解决方案。 - Mirza Obaid
7
哇!这需要一些工作,但是为了补充 @GeneKelly 关于使用 grecaptcha.getResponse(0)grecaptcha.getResponse(1) 来验证多个实例的说明,我想要补充一点,就是索引必须与 grecaptcha.render 的排序相对应。例如,在此示例中,grecaptcha.render('RecaptchaField1'... 将使用 grecaptcha.getResponse(0) 进行验证,而 grecaptcha.render('RecaptchaField2'... 则将使用 grecaptcha.getResponse(1) 进行验证,以此类推。 - codacopia
1
问题在于,当您执行grecaptcha.execute()时,回调函数仅针对第一个具有验证码的div进行调用,而不管您单击哪个位置。 - Eugen Konkov
显示剩余5条评论

85

简单明了:

  1. 使用以下方式正常创建您的Recaptcha字段:

    <div class="g-recaptcha" data-sitekey="YOUR_KEY_HERE"></div>
    
  2. 使用以下代码加载脚本:

    <script src="https://www.google.com/recaptcha/api.js?onload=CaptchaCallback&render=explicit" async defer></script>
    
    现在调用此函数来遍历字段并创建Recaptcha:
  3. 现在调用此函数来遍历字段并创建Recaptcha:

  4. <script type="text/javascript">
      var CaptchaCallback = function() {
        jQuery('.g-recaptcha').each(function(index, el) {
            grecaptcha.render(el, {
                'sitekey' : jQuery(el).attr('data-sitekey')
                ,'theme' : jQuery(el).attr('data-theme')
                ,'size' : jQuery(el).attr('data-size')
                ,'tabindex' : jQuery(el).attr('data-tabindex')
                ,'callback' : jQuery(el).attr('data-callback')
                ,'expired-callback' : jQuery(el).attr('data-expired-callback')
                ,'error-callback' : jQuery(el).attr('data-error-callback')
            });
        });
      };
    </script>
    

4
我认为这是正确的方式,因为它具有动态性,我可以无限制地创建实例而不需要定义静态ID。 - Greg Alexander
1
如果您需要手动提取验证码代码(例如在ajax请求中),请查看我的答案 - VanDir
请您看一下我的问题(https://dev59.com/xKDia4cB1Zd3GeqPGZy2#43211428)?POST参数为空。 - Marcio Mazzucato
3
"data-sitekey="YOUR_KEY_HERE"" 可以从 div 中删除,它是无用的(如果你需要更改 key,则需要编辑的地方更少)。 - the_nuts
3
实际上你在那里打错了一个字。属性data-sitekey是必需的,如果你有多个sitekey,这使得它变得更加动态。正确的行应该是grecaptcha.render(el, {'sitekey' : $(el).attr('data-sitekey') }); - Gkiokan
显示剩余4条评论

16

这个答案是对@raphadko的答案的扩展。

如果你需要手动提取验证码(比如在ajax请求中),你需要调用:

grecaptcha.getResponse(widget_id)

但是你如何获取小部件ID参数?

我使用CaptchaCallback的定义来存储每个g-recaptcha框的widget id(作为HTML数据属性):

var CaptchaCallback = function() {
    jQuery('.g-recaptcha').each(function(index, el) {
        var widgetId = grecaptcha.render(el, {'sitekey' : 'your code'});
        jQuery(this).attr('data-widget-id', widgetId);
    });
};

然后我可以调用:

grecaptcha.getResponse(jQuery('#your_recaptcha_box_id').attr('data-widget-id'));

提取代码。


2
嘿,谢谢你。#your_recaptcha_box_id是什么? - Lucas Bustamante
这在ajax中对我非常有效,但是-如果表单出现错误(例如,用户未找到),并且从ajax方法返回相关错误,则通常会通过调用grecaptcha.reset();来重置验证码,在单个表单每页设置中效果很好。但是在每页多个表单的情况下,此“重置”命令不会影响/重置验证码。我也尝试调用CaptchaCallback函数,但它没有解决问题。 - kneidels
回答我的评论。请参见:https://dev59.com/t4zda4cB1Zd3GeqPsOLE - kneidels

14

有一个类似的问题曾经在 ASP 页面上被问过(链接),那里的共识是使用 recaptcha 不可能实现。似乎多个表单必须共享验证码,除非你愿意使用不同的验证码。如果你没有被限制使用 recaptcha,则可以看一下 Zend 框架的 Zend_Captcha 组件 (链接)。它包含了一些


12
实际上,使用reCAPTCHA是可以的,但是没有JavaScript是不可能的。大多数浏览器都支持JavaScript,并且默认的ReCaptcha也使用JavaScript,因此这个解决方案很好。Hüseyin Yağlı的答案解释了这个解决方案。该解决方案的reCAPTCHA文档在 https://developers.google.com/recaptcha/docs/display#explicit_render。然而,我不知道如果没有JavaScript支持需要做什么来解决这个问题。 - Edward
1
实际上,使用reCAPTCHA是完全可能的。 - Carlos Espinoza

13

使用jQuery的clone()函数很容易实现此操作。

因此,您必须为reCAPTCHA创建两个包装器div。我的第一个表单的reCAPTCHA div:

<div id="myrecap">
    <?php
        require_once('recaptchalib.php');
        $publickey = "XXXXXXXXXXX-XXXXXXXXXXX";
        echo recaptcha_get_html($publickey);
    ?>
</div>
第二个表单的div为空(ID不同)。所以我的只是:
<div id="myraterecap"></div>

然后 JavaScript 就很简单了:

$(document).ready(function() {
    // Duplicate our reCapcha 
    $('#myraterecap').html($('#myrecap').clone(true,true));
});

在使用clone()时,可能不需要第二个参数传入true值,但有它也没什么坏处...这种方法唯一的问题是,如果你通过ajax提交表单,那么问题在于你有两个具有相同名称的元素,你必须以更聪明的方式捕获正确元素的值(两个reCaptcha元素的id分别为#recaptcha_response_field#recaptcha_challenge_field,以防万一有人需要)。


当您请求新的验证码时,您可能会遇到问题,因为它只会更新一个验证码实例。 - Ogugua Belonwu
这意味着只有原始验证码(第一个称为<div id="myrecap">的)将被刷新,其他验证码不会被刷新。 - Oxi
实际上,Oxi,你所关注的问题已经在我的先前评论中得到了解决。 - Serj Sagan
1
你可能做错了...怎么样在jsfiddle.net上提供你的代码链接?无论如何,现在不再需要这样做了...你应该使用Hüseyin Yağlı的答案。 - Serj Sagan

9

我知道这个问题已经有些年头了,但如果将来有人需要查找这个问题的话,我想说在同一页上放置两个验证码是可能的。官方文档链接如下:https://developers.google.com/recaptcha/docs/display下面的示例只是文件中的一个副本,你不必指定不同的布局。

<script type="text/javascript">
  var verifyCallback = function(response) {
    alert(response);
  };
  var widgetId1;
  var widgetId2;
  var onloadCallback = function() {
    // Renders the HTML element with id 'example1' as a reCAPTCHA widget.
    // The id of the reCAPTCHA widget is assigned to 'widgetId1'.
    widgetId1 = grecaptcha.render('example1', {
      'sitekey' : 'your_site_key',
      'theme' : 'light'
    });
    widgetId2 = grecaptcha.render(document.getElementById('example2'), {
      'sitekey' : 'your_site_key'
    });
    grecaptcha.render('example3', {
      'sitekey' : 'your_site_key',
      'callback' : verifyCallback,
      'theme' : 'dark'
    });
  };
</script>

8
grecaptcha.getResponse() 方法接受一个可选的 "widget_id" 参数,如果未指定,则默认为创建的第一个小部件。每个小部件都会从 grecaptcha.render() 方法返回一个 widget_id,它与 reCAPTCHA 容器的 id 属性无关!! 每个 reCAPTCHA 都有自己的响应数据。您必须为 reCAPTCHA div 分配一个 ID,并将其传递给 getResponse 方法:
例如:
<div id="reCaptchaLogin"
     class="g-recaptcha required-entry"
     data-sitekey="<?php echo $this->helper('recaptcha')->getKey(); ?>"
     data-theme="<?php echo($this->helper('recaptcha')->getTheme()); ?>"
     style="transform:scale(0.82);-webkit-transform:scale(0.82);transform-origin:0 0;-webkit-transform-origin:0 0;">
</div>


<script type="text/javascript">
  var CaptchaCallback = function() {
    jQuery('.g-recaptcha').each(function(index, el) {
        grecaptcha.render(el, {
            'sitekey' : jQuery(el).attr('data-sitekey')
            ,'theme' : jQuery(el).attr('data-theme')
            ,'size' : jQuery(el).attr('data-size')
            ,'tabindex' : jQuery(el).attr('data-tabindex')
            ,'callback' : jQuery(el).attr('data-callback')
            ,'expired-callback' : jQuery(el).attr('data-expired-callback')
            ,'error-callback' : jQuery(el).attr('data-error-callback')
        });
    });
  };
</script>

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

访问响应:

var reCaptchaResponse = grecaptcha.getResponse(0);

或者
var reCaptchaResponse = grecaptcha.getResponse(1);

2
哇,谢谢!在官方文档中找不到这样的东西。 这样,您可以拥有多个验证码,而无需进行显式渲染。我有一个情况,在整个网站的各个地方都有正常的渲染,但只需要在一个地方进行显式渲染 - 这解决了我的问题。 - Svetoslav Stefanov

4
这是一个没有使用JQuery的答案版本,由raphadkonoun提供。
1)通过以下方式正常创建您的reCAPTCHA字段:
<div class="g-recaptcha"></div>

2) 使用以下代码加载脚本:

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

3) 现在调用它来迭代字段并创建recaptchas:

var CaptchaCallback = function() {
    var captchas = document.getElementsByClassName("g-recaptcha");
    for(var i = 0; i < captchas.length; i++) {
        grecaptcha.render(captchas[i], {'sitekey' : 'YOUR_KEY_HERE'});
    }
};

4
我是一个有用的助手,可以翻译文本。
我在页脚中有联系表格,它始终显示,并且某些页面(如创建帐户)也可能具有验证码,因此它是动态的,我正在使用以下方式与jQuery:
HTML:
<div class="g-recaptcha" id="g-recaptcha"></div>

<div class="g-recaptcha" id="g-recaptcha-footer"></div>

JavaScript
<script src="https://www.google.com/recaptcha/api.js?onload=CaptchaCallback&render=explicit&hl=en"></script>
<script type="text/javascript">
  var CaptchaCallback = function(){        
      $('.g-recaptcha').each(function(){
        grecaptcha.render(this,{'sitekey' : 'your_site_key'});
      })
  };
</script>

2
raphadko的回答 增加一些内容:由于您有多个验证码(在一个页面上),因此无法使用(通用的)g-recaptcha-response POST参数(因为它仅包含一个验证码的响应)。相反,您应该为每个验证码使用grecaptcha.getResponse(opt_widget_id)调用。这是我的代码(假设每个验证码都在其表单内):

HTML:

<form ... />

<div id="RecaptchaField1"></div>

<div class="field">
  <input type="hidden" name="grecaptcha" id="grecaptcha" />
</div>

</form>

并且

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

JavaScript:
var CaptchaCallback = function(){
    var widgetId;

    $('[id^=RecaptchaField]').each(function(index, el) {

         widgetId = grecaptcha.render(el.id, {'sitekey' : 'your_site_key'});

         $(el).closest("form").submit(function( event ) {

            this.grecaptcha.value = "{\"" + index + "\" => \"" + grecaptcha.getResponse(widgetId) + "\"}"

         });
    });
};

请注意,我将事件委托(参见添加元素后刷新DOM)应用于所有动态修改的元素。这将把每个验证码的响应绑定到其所在表单的submit事件上。

1
哇,我找了好几个小时才找到这个。谢谢!! - Black

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