Как решить проблему тайм-аута Google v3 reCAPTCHA?

#php #invisible-recaptcha #recaptcha-v3

#php #невидимый-recaptcha #recaptcha-v3

Вопрос:

У нас есть PHP-форма с несколькими вкладками и тайм-аутом в рекапче. Все делается на одной странице, и она отлично работает, если форма заполняется менее чем за 3 минуты.

Идея решения состоит в том, чтобы переместить обработку формы и рекапчу на дополнительную страницу для обработки.

Проблема в том, что страница формы опрашивает службу Google на наличие reCAPTCHA и собирает значение токена в скрытое поле.

 <input type="hidden" name="recaptcha_response" id="recaptchaResponse">
  

Проблема в том, как запросить этот токен на странице обработки на стороне сервера? Вот код, используемый на странице формы на стороне клиента. Мне нужно каким-то образом восстановить значение токена, чтобы применить как :

$recaptcha_response

Вот рабочая версия на странице формы. Легко удалить требование о публикации токена со страницы формы, просто не уверен, как повторно создать токен для использования на странице на стороне сервера.

 if ($_SERVER['REQUEST_METHOD'] === 'POST' amp;amp; isset($_POST['recaptcha_response'])) {

// Build POST request:
$recaptcha_url = 'https://www.google.com/recaptcha/api/siteverify';
$recaptcha_secret = RECAPTCHA_SECRET_KEY;
$recaptcha_response = $_POST['recaptcha_response'];
$remoteip = $_SERVER['REMOTE_ADDR'];

// Make and decode POST request:
$recaptcha = file_get_contents($recaptcha_url . '?secret=' . $recaptcha_secret . 'amp;response=' . $recaptcha_response. 'amp;remoteip='.$remoteip);
$recaptcha = json_decode($recaptcha);

// Take action based on the score returned:
if ($recaptcha->score >= 0.5) {
  

ОТРЕДАКТИРУЙТЕ, ЧТОБЫ ДОБАВИТЬ:
Приведет ли инициализация reCAPTCHA до отправки к задержке проблемы с синхронизацией, поскольку это, похоже, вариант:

https://developers.google.com/recaptcha/docs/v3

«2. Вызовите grecaptcha.execute при выполнении действия или при загрузке страницы»

Комментарии:

1. Ваша серверная часть выглядит нормально и т.д., Но клиентской стороне потребуется другое выполнение grecaptcha.ready( функция() { grecaptcha.execute(… ); })

2. Вы говорите, что решение состоит в том, чтобы не переходить на дополнительную страницу (которая работает сейчас, если <~ 3 минуты), а повторно выполнить отправку и получение токена перед отправкой отправки?

3. это зависит от того, когда вам нужна информация о капче, если она вам нужна, и срок ее действия истек, тогда единственный способ получить ее снова — это попросить клиента (браузер) запросить токен, а сервер его проверить. лично я, как только я верифицирую клиент, мне не нужно повторно проверять его — даже через 10 минут.

4. Поэтому вместо отправки проверьте клиент при загрузке страницы, что затем устраняет возможность тайм-аута. Это еще одна концепция, и в ней есть смысл!

Ответ №1:

Если вы не хотите слишком сильно изменять свой код, альтернативным подходом было бы обернуть reCAPTCHA JavaScript в именованную функцию, установить интервал и опросить эту функцию, предлагая reCAPTCHA добавлять новый токен в ваш элемент формы за 10 секунд до истечения срока действия каждого двухминутного токена:

 function getReCaptcha(){
    grecaptcha.ready(function() {
       ...
     });
 }

 getReCaptcha();  // This is the initial call
 setInterval(function(){getReCaptcha();}, 110000);
  

Комментарии:

1. Это должно быть отмечено как правильный ответ для этой проблемы, хотя я установил для своего setInterval значение 90 * 1000 миллисекунд, поскольку в документации Google указано, что тайм-аут токена составляет 120 секунд.

2. Хороший ответ. Хотя в вашем примере показано 2,5 минуты, а не 3.

3. Спасибо за комментарии о сроке службы токена reCaptha. Я поверил оператору на слово, что срок службы составляет 3 минуты, и в документации Google достаточно верно сказано, что токен имеет срок службы всего 2 минуты. Я обновил свой ответ, чтобы получать новый токен каждые 110 секунд, а не каждые 150 секунд.

Ответ №2:

Мы тоже сталкивались с этим недавно. Я нашел это решение на GitHub, и у нас оно хорошо работает.

Преимущество этого заключается в том, что токен запрашивается только тогда, когда пользователь взаимодействует со страницей (например, отправляет форму), вместо того, чтобы постоянно запрашивать его.

 <script>
  grecaptcha.ready(function() {
      document.getElementById('contactform').addEventListener("submit", function(event) {

        event.preventDefault();

        grecaptcha.execute('mykey', {action: 'homepage'}).then(function(token) {
           document.getElementById("googletoken").value = token; 
           document.getElementById('contactform').submit();
        });        
      }, false);

  });
</script>
  

Комментарии:

1. Спасибо, я попробую ваш метод в следующий раз, когда мы будем кодировать что-то подобное.

2. Только что столкнулся с той же проблемой и реализовал метод с использованием именованной функции и прослушивания «отправить», и это сработало отлично.

3. rifton 007 прокомментировал 13 февраля @iwasherefirst2, что решение не идеально. Потому что, когда мы запрашиваем токен непосредственно перед отправкой. Форме требуется подождать несколько секунд, чтобы получить токен и отправить с данными.

4. Это правда, поэтому в этом случае вы можете просто показать какой-нибудь «рабочий» индикатор сразу после event.preventDefault(); , чтобы пользователь знал, что форма отправляется, что должно решить большинство проблем.

Ответ №3:

 <script type="text/javascript">
function grecaptcha_execute(){
    grecaptcha.execute('RECAPTCHA_SITE_KEY', {action: 'homepage'}).then(function(token) {
        document.getElementById('recaptchaResponse').value=token;
    });
}
grecaptcha.ready(function() {
    grecaptcha_execute();
});
</script>

<?php
if ($recaptcha->success) {
    echo '<p style="color: #0a860a;">CAPTCHA was completed successfully!</p>';
}else{
    $error_codes = 'error-codes';
    if (isset($Retorno->$error_codes) amp;amp; in_array("timeout-or-duplicate", $Retorno->$error_codes)) {
        $captcha_msg = "The verification expired due to timeout, please try again.";
    ?>
    <script>grecaptcha_execute();</script>
    <?php
    } else {
        $captcha_msg = "Check to make sure your keys match the registered domain and are in the correct locations.<br> You may also want to doublecheck your code for typos or syntax errors.";
    }
    echo '<p style="color: #f80808;">reCAPTCHA error: ' . $captcha_msg . '</p>';
}
?>
  

Ответ №4:

Загрузите reCAPTCHA API js и Jquery (если вы используете код jquery):

 <script src="https://www.google.com/recaptcha/api.js?render=SITE_KEY"></script>
<script  src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
  

Рекапча отображает Javascript:

   <script type="text/javascript">
     $(document).ready(function(){
        setInterval(function(){
        grecaptcha.ready(function() {
            grecaptcha.execute('SITE_KEY', {action: 'home'}).then(function(token) {
                $('#recaptchaResponse').val(token);
            });
        });
        }, 3000); //you can set timeout for expired.
     });
     
  </script>
  

Изменение сайта:

 <?php 
    if ($_SERVER['REQUEST_METHOD'] === 'POST' amp;amp; isset($_POST['submit'])) {
        if(isset($_POST['recaptcha_response']) amp;amp; !empty($_POST['recaptcha_response'])){
            $recaptcha_url = 'https://www.google.com/recaptcha/api/siteverify';
            $recaptcha_secret = 'SECRET_KEY';
            $recaptcha_response = $_POST['recaptcha_response'];
            $response = file_get_contents($recaptcha_url . '?secret=' . $recaptcha_secret . 'amp;response=' . $recaptcha_response);
            $recaptcha = json_decode($response);
            if ($recaptcha->success == true amp;amp; $recaptcha->score >= 0.5) {
                echo $response;
                echo '<br>Form Submitted Successfully';
            } else { 
                echo $response;
                echo '<br>reCaptcha varification failed';
            }
        }else {
            echo 'reCaptcha is empty';
        } 
    }
?>
  

HTML-форма:

 <form method="POST">
    <label class="label">Name</label>
    <input type="text" name="name" class="input" placeholder="Name" required>
    <button type="submit" name="submit" class="button is-link">Send Message</button>
    <input type="hidden" name="recaptcha_response" id="recaptchaResponse">
</form>
  

Ответ №5:

Игнорируйте все остальное здесь. Причины:

  1. Если вы просто сгенерируете токен при загрузке страницы, время ожидания истечет через 2 минуты, что означает, что пользователям это не понравится
  2. Обновление токенов будет стоить вам (есть бесплатный уровень, но он стоит после использования X запросов)

Решение: Сгенерируйте токен во время отправки формы! https://jsfiddle.net/skobaljic/rL6fux5w/2

 var webQueryForm = $('#webQuery');
webQueryForm.submit(function(event) {
  e.preventDefault();
  grecaptcha.execute('MYSITEKEY(PUBLIC)', {
     action: 'contact'
     }).then(function(token) {
     $('#recaptchaToken').val(token);
    webQueryForm.submit();
  });
});
  

Ответ №6:

При использовании grecaptcha.execute() это не устраняет проблему. Потому что execute () также может выдавать ошибку. Чтобы решить эту проблему, вы должны поместить execute в блок try-catch. Например:

 grecaptcha.ready(function() {
    try {
      grecaptcha.execute('RECAPTCHA_SITE_KEY', {action: 'submit'})
        .then(function(token) {
            submitYourForm(token);
        })
    } catch (error) {
        yourRetryBlockHere();
    }
});