谷歌Recaptcha v3示例演示

97

到目前为止,我一直在使用Google Recaptcha v2,但现在我想通过使用最新版本(v3)来更新我的WebApp。

是否有人可以添加一个完全正常工作的Google Recaptcha v3示例,以供基本表单使用,因为我找不到任何有效的演示呢?

我真的很感激。

非常感谢。

附言:我在服务器端使用Java Servlets,但如果您使用PHP或其他语言进行解释也没有关系。


2
这是链接:https://recaptcha-demo.appspot.com/ 只需请求v3的分数,它将以JSON格式返回响应。 - Suleman
11
我已经创建了一个演示,但是它是用PHP编写的。 访问我的博客链接 - PHP Kishan
但是我怎么把它放在div里面呢? - Freddy Sidauruk
@FreddySidauruk,你不需要放置在div中,它是通过调用Google API的JavaScript函数来执行的,然后会像recaptchav2一样返回响应。 - Suleman
例如,单击按钮时,您可以调用此函数:grecaptcha.execute(“ Recaptcha v3网站密钥”,{ action:'test'}) .then((token)=> { console.log(token)}) - Suleman
1
我在这里发布了一个简单但详细的纯JS和PHP演示:https://dev59.com/91UL5IYBdhLWcg3waHRw#57202461 - wkille
8个回答

137

实现ReCaptcha v3的简单代码

基本的JS代码

<script src="https://www.google.com/recaptcha/api.js?render=your reCAPTCHA site key here"></script>
<script>
    grecaptcha.ready(function() {
    // do request for recaptcha token
    // response is promise with passed token
        grecaptcha.execute('your reCAPTCHA site key here', {action:'validate_captcha'})
                  .then(function(token) {
            // add token value to form
            document.getElementById('g-recaptcha-response').value = token;
        });
    });
</script>

基本的HTML代码

<form id="form_id" method="post" action="your_action.php">
    <input type="hidden" id="g-recaptcha-response" name="g-recaptcha-response">
    <input type="hidden" name="action" value="validate_captcha">
    .... your fields
</form>

基本的PHP代码

if (isset($_POST['g-recaptcha-response'])) {
    $captcha = $_POST['g-recaptcha-response'];
} else {
    $captcha = false;
}

if (!$captcha) {
    //Do something with error
} else {
    $secret   = 'Your secret key here';
    $response = file_get_contents(
        "https://www.google.com/recaptcha/api/siteverify?secret=" . $secret . "&response=" . $captcha . "&remoteip=" . $_SERVER['REMOTE_ADDR']
    );
    // use json_decode to extract json response
    $response = json_decode($response);

    if ($response->success === false) {
        //Do something with error
    }
}

//... The Captcha is valid you can continue with the rest of your code
//... Add code to filter access using $response . score
if ($response->success==true && $response->score <= 0.5) {
    //Do something to denied access
}

你需要使用$response.score的值来过滤访问。它可以取0.0到1.0之间的值,其中1.0表示用户与您的站点的最佳交互,而0.0表示最差的交互(例如机器人)。您可以在ReCaptcha文档中查看一些使用示例。


5
你发布的代码没有检查 score 字段的值;如果我正确理解了文档success 只表示所发送的请求是否有效;关于交互(即合法与否)的实际信息存储在 score 字段中。 - user4520
19
文档里写了:注意:reCAPTCHA令牌在两分钟后会过期。如果你正在使用reCAPTCHA保护一个动作,请确保在用户执行该动作时调用execute。然而,你在库加载后就调用了execute。我会修复这个问题。 - Adam
5
人们不禁想要知道,为什么他们要求开发者通过两次验证才能获得密钥。 - cdosborn
18
我想知道这样一个糟糕的例子为什么会有这么多赞。 - Pedro Lobito
3
在尝试了多个答案(包括这个)都没有成功之后,我在这个答案上得到了更多的帮助。 - ashleedawg
显示剩余7条评论

30

我觉得使用Bootstrap 4表单编写的PHP完整reCaptcha v3示例演示可能对某些人有用。

参考所示依赖项,替换您的电子邮件地址和密钥(在此处创建您自己的密钥here),表单已准备好进行测试和使用。我添加了代码注释以更好地澄清逻辑,并包括了注释掉的console.log和print_r行,以快速启用从Google生成的验证令牌和数据的查看。

包含的jQuery函数是可选的,但它确实为此演示创建了更好的用户提示体验。


PHP文件(mail.php):

在指定位置添加密钥(2个地方)和电子邮件地址。

<?php

if ($_SERVER["REQUEST_METHOD"] == "POST") {

  # BEGIN Setting reCaptcha v3 validation data
  $url = "https://www.google.com/recaptcha/api/siteverify";
  $data = [
    'secret' => "your-secret-key-here",
    'response' => $_POST['token'],
    'remoteip' => $_SERVER['REMOTE_ADDR']
  ];

  $options = array(
    'http' => array(
      'header'  => "Content-type: application/x-www-form-urlencoded\r\n",
      'method'  => 'POST',
      'content' => http_build_query($data)
    )
    );
  
  # Creates and returns stream context with options supplied in options preset 
  $context  = stream_context_create($options);
  # file_get_contents() is the preferred way to read the contents of a file into a string
  $response = file_get_contents($url, false, $context);
  # Takes a JSON encoded string and converts it into a PHP variable
  $res = json_decode($response, true);
  # END setting reCaptcha v3 validation data
   
    // print_r($response); 
# Post form OR output alert and bypass post if false. NOTE: score conditional is optional
# since the successful score default is set at >= 0.5 by Google. Some developers want to
# be able to control score result conditions, so I included that in this example.

  if ($res['success'] == true && $res['score'] >= 0.5) {
 
    # Recipient email
    $mail_to = "youremail@domain.com";
    
    # Sender form data
    $subject = trim($_POST["subject"]);
    $name = str_replace(array("\r","\n"),array(" "," ") , strip_tags(trim($_POST["name"])));
    $email = filter_var(trim($_POST["email"]), FILTER_SANITIZE_EMAIL);
    $phone = trim($_POST["phone"]);
    $message = trim($_POST["message"]);
    
    if (empty($name) OR !filter_var($email, FILTER_VALIDATE_EMAIL) OR empty($phone) OR empty($subject) OR empty($message)) {
      # Set a 400 (bad request) response code and exit
      http_response_code(400);
      echo '<p class="alert-warning">Please complete the form and try again.</p>';
      exit;
    }

    # Mail content
    $content = "Name: $name\n";
    $content .= "Email: $email\n\n";
    $content .= "Phone: $phone\n";
    $content .= "Message:\n$message\n";

    # Email headers
    $headers = "From: $name <$email>";

    # Send the email
    $success = mail($mail_to, $subject, $content, $headers);
    
    if ($success) {
      # Set a 200 (okay) response code
      http_response_code(200);
      echo '<p class="alert alert-success">Thank You! Your message has been successfully sent.</p>';
    } else {
      # Set a 500 (internal server error) response code
      http_response_code(500);
      echo '<p class="alert alert-warning">Something went wrong, your message could not be sent.</p>';
    }   

  } else {

    echo '<div class="alert alert-danger">
        Error! The security token has expired or you are a bot.
       </div>';
  }  

} else {
  # Not a POST request, set a 403 (forbidden) response code
  http_response_code(403);
  echo '<p class="alert-warning">There was a problem with your submission, please try again.</p>';
} ?>

HTML <head>

Bootstrap CSS 依赖和 reCaptcha 客户端验证 放置在 <head> 标签之间 - 在指定位置粘贴您自己的站点密钥。

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
<script src="https://www.google.com/recaptcha/api.js?render=your-site-key-here"></script>

HTML <body>

放置在<body> 标签之间。


<!-- contact form demo container -->
<section style="margin: 50px 20px;">
  <div style="max-width: 768px; margin: auto;">
    
    <!-- contact form -->
    <div class="card">
      <h2 class="card-header">Contact Form</h2>
      <div class="card-body">
        <form class="contact_form" method="post" action="mail.php">

          <!-- form fields -->
          <div class="row">
            <div class="col-md-6 form-group">
              <input name="name" type="text" class="form-control" placeholder="Name" required>
            </div>
            <div class="col-md-6 form-group">
              <input name="email" type="email" class="form-control" placeholder="Email" required>
            </div>
            <div class="col-md-6 form-group">
              <input name="phone" type="text" class="form-control" placeholder="Phone" required>
            </div>
            <div class="col-md-6 form-group">
              <input name="subject" type="text" class="form-control" placeholder="Subject" required>
            </div>
            <div class="col-12 form-group">
              <textarea name="message" class="form-control" rows="5" placeholder="Message" required></textarea>
            </div>

            <!-- form message prompt -->
            <div class="row">
              <div class="col-12">
                <div class="contact_msg" style="display: none">
                  <p>Your message was sent.</p>
                </div>
              </div>
            </div>

            <div class="col-12">
              <input type="submit" value="Submit Form" class="btn btn-success" name="post">
            </div>

            <!-- hidden reCaptcha token input -->
            <input type="hidden" id="token" name="token">
          </div>

        </form>
      </div>
    </div>

  </div>
</section>
<script>
  grecaptcha.ready(function() {
    grecaptcha.execute('your-site-key-here', {action: 'homepage'}).then(function(token) {
       // console.log(token);
       document.getElementById("token").value = token;
    });
    // refresh token every minute to prevent expiration
    setInterval(function(){
      grecaptcha.execute('your-site-key-here', {action: 'homepage'}).then(function(token) {
        console.log( 'refreshed token:', token );
        document.getElementById("token").value = token;
      });
    }, 60000);

  });
</script>

<!-- References for the optional jQuery function to enhance end-user prompts -->
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="form.js"></script>

增强用户体验的可选jQuery功能(form.js):


(function ($) {
'use strict';

var form = $('.contact_form'),
  message = $('.contact_msg'),
  form_data;

// Success function
function done_func(response) {
  message.fadeIn()
  message.html(response);
  setTimeout(function () {
    message.fadeOut();
  }, 10000);
  form.find('input:not([type="submit"]), textarea').val('');
}

// fail function
function fail_func(data) {
  message.fadeIn()
  message.html(data.responseText);
  setTimeout(function () {
    message.fadeOut();
  }, 10000);
}

form.submit(function (e) {
  e.preventDefault();
  form_data = $(this).serialize();
  $.ajax({
    type: 'POST',
    url: form.attr('action'),
    data: form_data
  })
  .done(done_func)
  .fail(fail_func);
}); })(jQuery);

3
非常彻底;在放弃其他(得分更高的)答案后,我很快就解决了这个问题。谢谢! - ashleedawg
2
注意:reCAPTCHA令牌在两分钟后过期。如果您正在使用reCAPTCHA保护某个操作,请确保在用户执行该操作时调用execute,而不是在页面加载时调用。这在评论表单上尤其重要——作为用户,在输入详细(冗长)的愤怒反馈后,网站的表单却无法让我提交,这可能会非常令人沮丧! - ashleedawg
2
@ashleedawg 编辑后,每60秒刷新令牌。 - Talk Nerdy To Me
@Albert 没有任何无知 - 看起来我提交的编辑被拒绝了。我猜 SO 只在编辑被接受时通知你?那个编辑真的会很有帮助,所以我不知道为什么它会被抛弃。我已经重新提交了编辑,希望这次不会被拒绝,如果被拒绝了,我会尽力解释的。 - Talk Nerdy To Me
1
您可以在此处获取您的SITE密钥和SECRET密钥:https://www.google.com/recaptcha/admin/create - timgavin
显示剩余7条评论

5
我假设您已经设置了网站密钥和密钥。请按照以下步骤操作。
在您的HTML文件中,添加脚本。
 <script src="https://www.google.com/recaptcha/api.js?render=put your site key here"></script>

此外,可以使用jQuery来轻松处理事件。
以下是简单的表单。
 <form id="comment_form" action="form.php" method="post" >
      <input type="email" name="email" placeholder="Type your email" size="40"><br><br>
      <textarea name="comment" rows="8" cols="39"></textarea><br><br>
      <input type="submit" name="submit" value="Post comment"><br><br>
    </form>

您需要初始化 Google reCAPTCHA 并监听准备就绪事件。以下是如何实现的方法。
您需要初始化 Google reCAPTCHA 并监听准备就绪事件。以下是如何实现的方法。
     <script>
       // when form is submit
    $('#comment_form').submit(function() {
        // we stoped it
        event.preventDefault();
        var email = $('#email').val();
        var comment = $("#comment").val();
        // needs for recaptacha ready
        grecaptcha.ready(function() {
            // do request for recaptcha token
            // response is promise with passed token
            grecaptcha.execute('put your site key here', {action: 'create_comment'}).then(function(token) {
                // add token to form
                $('#comment_form').prepend('<input type="hidden" name="g-recaptcha-response" value="' + token + '">');
                $.post("form.php",{email: email, comment: comment, token: token}, function(result) {
                        console.log(result);
                        if(result.success) {
                                alert('Thanks for posting comment.')
                        } else {
                                alert('You are spammer ! Get the @$%K out.')
                        }
                });
            });
        });
  });
  </script>

这是一个示例PHP文件。您可以使用Servlet或Node或任何后端语言来替代它。
<?php

        $email;$comment;$captcha;
        if(isset($_POST['email'])){
          $email=$_POST['email'];
        }if(isset($_POST['comment'])){
          $comment=$_POST['comment'];
        }if(isset($_POST['token'])){
          $captcha=$_POST['token'];
          }
        if(!$captcha){
          echo '<h2>Please check the the captcha form.</h2>';
          exit;
        }
        $secretKey = "put your secret key here";
        $ip = $_SERVER['REMOTE_ADDR'];

        // post request to server

        $url =  'https://www.google.com/recaptcha/api/siteverify?secret=' . urlencode($secretKey) .  '&response=' . urlencode($captcha);
        $response = file_get_contents($url);
        $responseKeys = json_decode($response,true);
        header('Content-type: application/json');
        if($responseKeys["success"]) {
                echo json_encode(array('success' => 'true'));
        } else {
                echo json_encode(array('success' => 'false'));
        }
?>

这是教程链接:https://codeforgeek.com/2019/02/google-recaptcha-v3-tutorial/,希望对您有所帮助。

8
这个是错误的,没有考虑到在v3版中需要的得分。不要按照此指南操作,建议阅读链接页面上的评论。 - tony
在尝试了几个答案(包括这个)都没有成功之后,我在这个答案上运气更好了。 - ashleedawg

3

我们只使用reCAPTCHA-V3来检查网站流量质量,并将其用作非阻塞式。 由于reCAPTCHA-V3不需要显示在网站上,可以作为隐藏使用,但您必须显示reCAPTCHA隐私等链接(建议如此)

head标签中的脚本标签

<script src="https://www.google.com/recaptcha/api.js?onload=ReCaptchaCallbackV3&render='SITE KEY' async defer></script>

注意:"async defer" 确保其非阻塞,这是我们的特定要求。
JS 代码:
<script>
    ReCaptchaCallbackV3 = function() {
        grecaptcha.ready(function() {
            grecaptcha.execute("SITE KEY").then(function(token) {
                $.ajax({
                    type: "POST",
                    url: `https://api.${window.appInfo.siteDomain}/v1/recaptcha/score`,
                    data: {
                        "token" : token,
                    },
                    success: function(data) {
                        if(data.response.success) {
                            window.recaptchaScore = data.response.score;
                            console.log('user score ' + data.response.score)
                        }
                    },
                    error: function() {
                        console.log('error while getting google recaptcha score!')
                    }
                });

            });
        });
    };
</script> 

HTML/Css 代码:

there is no html code since our requirement is just to get score and don't want to show recaptcha badge.

后端 - Laravel 代码:

Route:

Route::post('/recaptcha/score', 'Api\\ReCaptcha\\RecaptchaScore@index');


Class:

class RecaptchaScore extends Controller
{
    public function index(Request $request)
    {
        $score = null;

        $response = (new Client())->request('post', 'https://www.google.com/recaptcha/api/siteverify', [
            'form_params' => [
                'response' => $request->get('token'),
                'secret' => 'SECRET HERE',
            ],
        ]);

        $score = json_decode($response->getBody()->getContents(), true);

        if (!$score['success']) {
            Log::warning('Google ReCaptcha Score', [
                'class' => __CLASS__,
                'message' => json_encode($score['error-codes']),
            ]);
        }

        return [
            'response' => $score,
        ];
    }
} 

我们获取分数并保存在变量中,以便在提交表单时使用。
参考: https://developers.google.com/recaptcha/docs/v3 https://developers.google.com/recaptcha/

在尝试了几个答案(包括这个)之后没有成功之后,我在这个答案上运气更好了。 - ashleedawg
@ashleedawg,如果这对你不起作用,我很抱歉!我刚刚再次测试了一下,看起来一切都很好!你的参考是一个简单的PHP实现,如果你使用我提到的这个解决方案,它是为#Laravel编写的,但如果你只是使用RecaptchaScore类,它也应该可以工作。 - Furqan Freed

3

我看过大多数不能正常工作的文章,这就是为什么新开发人员和专业开发人员会感到困惑的原因。

我将以非常简单的方式向您解释。在此代码中,我在每3秒的时间间隔内在客户端生成一个Google Recaptcha令牌,因为该令牌仅在几分钟内有效,如果用户需要花费一些时间填写表格,则可能会过期。

首先,我有一个index.php文件,在其中编写HTML和JavaScript代码。

    <!DOCTYPE html>
<html>
   <head>
      <title>Google Recaptcha V3</title>
   </head>
   <body>
      <h1>Google Recaptcha V3</h1>
      <form action="recaptcha.php" method="post">
         <label>Name</label>
         <input type="text" name="name" id="name">
         <input type="hidden" name="token" id="token" /> 
         <input type="hidden" name="action" id="action" /> 
         <input type="submit" name="submit">
      </form>
      <script src="https://www.google.com/recaptcha/api.js?render=put your site key here"></script>
      <script  src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
      <script type="text/javascript">
         $(document).ready(function(){
            setInterval(function(){
            grecaptcha.ready(function() {
                grecaptcha.execute('put your site key here', {action: 'application_form'}).then(function(token) {
                    $('#token').val(token);
                    $('#action').val('application_form');
                });
            });
            }, 3000);
         });

      </script>
   </body>
</html>

接下来,我创建了recaptcha.php文件以在服务器端执行。
<?php

if ($_POST['submit']) {
    $name   = $_POST['name'];
    $token  = $_POST['token'];
    $action = $_POST['action'];

    $curlData = array(
        'secret' => 'put your secret key here',
        'response' => $token
    );

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, "https://www.google.com/recaptcha/api/siteverify");
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($curlData));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $curlResponse = curl_exec($ch);

    $captchaResponse = json_decode($curlResponse, true);

    if ($captchaResponse['success'] == '1' && $captchaResponse['action'] == $action && $captchaResponse['score'] >= 0.5 && $captchaResponse['hostname'] == $_SERVER['SERVER_NAME']) {
        echo 'Form Submitted Successfully';
    } else {
        echo 'You are not a human';
    }
}

此代码来源。如果您想了解此代码的解释,请访问在PHP中集成Google reCAPTCHA V3


我同意你的第一句话...但这对我也没用 ("You are not a human"). 对我有用的唯一答案是这个 - ashleedawg
嗨@clayray,我已经在代码中应用了分数。 - Sumit Kumar Gupta
啊是的,你有@SumitKumarGupta。抱歉,我会删除我的评论。 - clayRay
1
这对我有用。网站密钥有两个位置,而秘密只有一个位置。不要错过它们,伙计们。 - Chris
我实现了V3并在提交时生成了reCAPTCHA令牌,当他们点击“提交”按钮时。无需每隔一段时间创建新的密钥。 - Kershaw
嗨@Kershaw,如果用户打开一个表单超过1或2个小时,则需要新的令牌。 - Sumit Kumar Gupta

2

如果你只需要一个“基本表单”(正如原问题所问),并且满足在服务器端进行验证,那么所需的内容非常简单。下面是一个完整的HTML页面:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<script src="https://www.google.com/recaptcha/api.js"></script>
<script>
<!--
function onSubmit() {
    var form = document.forms[0];
    if ( form['name'].value ) {
        form.submit();
    } else {
        alert( 'Please provide a name.' );
    }
}
//-->
</script> 
</head>
<body>
    <form action="process.asp" method="post">
        Name: <input type="text" name="name" /><br /><br />
        <button class="g-recaptcha" data-sitekey="SITE_KEY" data-callback='onSubmit' data-action='contact'>Send</button>
    </form>
</body>
</html>

这是一个完整的页面,用于处理它,使用经典ASP(文件名=process.asp)以简化操作:

<%@ Language=JavaScript %>
<%
var name = Request( 'name' ).Item;
var recaptchaResponse = Request( 'g-recaptcha-response' ).Item;
var ip = Request.ServerVariables( 'REMOTE_ADDR' );
var xmlhttp = Server.CreateObject( 'MSXML2.ServerXMLHTTP' );
var query = 'secret=SECRET_KEY&response=' + recaptchaResponse + '&remoteip=' + ip;
xmlhttp.open( 'POST', 'https://www.google.com/recaptcha/api/siteverify?' + query, false ); // false says to wait for response
xmlhttp.send();
var response = JSON.parse( xmlhttp.responseText );
Response.Write( name + ' is a ' + (response.success && response.action == 'contact' && response.score > 0.5 ? 'HUMAN' : 'ROBOT') );
%>

一些注意事项:

  1. 你需要提供自己的SITE_KEY和SECRET_KEY。
  2. 你需要一个JSON解析器。
  3. 你需要使用适合你服务器的方法进行服务器端POST。
  4. 我添加了一个简单的表单字段验证,以便你了解如何集成它。
  5. 你可以将"action"字符串设置为任何你想要的内容,但请确保服务器上的内容与HTML中的内容一致。
  6. 你可能需要对response.success不为true或response.action与你的action字符串不匹配等情况做出不同的响应,或者进行其他错误检查。
  7. 你可能需要一个不同于"> 0.5"的分数条件。
  8. 这段代码没有两分钟超时的问题。

2
我从Angular的Ajax调用中处理PHP的POST。我也想看到来自Google的SCORE。
这对我很有效...
$postData = json_decode(file_get_contents('php://input'), true); //get data sent via post
$captcha = $postData['g-recaptcha-response'];

header('Content-Type: application/json');
if($captcha === ''){
    //Do something with error
    echo '{ "status" : "bad", "score" : "none"}';
} else {
    $secret   = 'your-secret-key';
    $response = file_get_contents(
        "https://www.google.com/recaptcha/api/siteverify?secret=" . $secret . "&response=" . $captcha . "&remoteip=" . $_SERVER['REMOTE_ADDR']
    );
    // use json_decode to extract json response
    $response = json_decode($response);

    if ($response->success === false) {
        //Do something with error
        echo '{ "status" : "bad", "score" : "none"}';
    }else if ($response->success==true && $response->score <= 0.5) {
        echo '{ "status" : "bad", "score" : "'.$response->score.'"}';
    }else {
        echo '{ "status" : "ok", "score" : "'.$response->score.'"}';
    }
}

关于HTML

<input type="hidden" id="g-recaptcha-response" name="g-recaptcha-response">

关于JS

$scope.grabCaptchaV3=function(){
     var myCaptcha = angular.element('#g-recaptcha-response').val();         
     var params = {
                     method: 'POST',
                     url: 'api/recaptcha.php',
                     headers: {
                       'Content-Type': undefined
                     },
                     data:   {'g-recaptcha-response' : myCaptcha }
     }
     $http(params).then(function(result){ 
                console.log(result.data);
     }, function(response){
                console.log(response.statusText);
     }); 
}

0
如果您正在首次在网站上实施reCAPTCHA,我建议添加api.js并让Google收集您的用户的行为数据1-2天。这样更加安全可靠,特别是在开始使用分数之前。

欢迎来到 Stack Overflow!更多信息或链接会很有帮助。(请查看[答案]。) - ashleedawg

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