Как дождаться токена reCAPTCHA v3 синхронно? - PullRequest
0 голосов
/ 26 мая 2020

Я привязан, и Javascript мир это очень странно.

Мне нужно создать форму с токеном reCAPTCHA v3 разрешено раньше приступаем к отправке формы. Поскольку некоторые события привязаны к форме submit event, событие l oop должно ждать, пока оно не будет разрешено, иначе оно завершится ошибкой:

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

Пока я пытаюсь сделать, это иметь слушателя для события submit, которое блокирует отправку, пока токен не будет разрешен , прежде чем продолжить с другими слушателями.

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

// Let's retrieve the form by its id.
let form = document.getElementById('example_form');

let addToken = (form) => {
    grecaptcha.execute('site_key', {
        // some options
    }).then(token => {
        // Include the token as an input inside the form so it's sent.
    });
};

form.addEventListener('submit', () => {
    return addToken(form); // <-- This won't work, since it's async.
});

Ответы [ 2 ]

0 голосов
/ 27 мая 2020

Разобрался, сделать recaptcha.execute() синхронным нет возможности. Другими словами, невозможно дождаться разрешения токена с серверов. чтобы быть уверенным, что токен получен до истечения срока.

Этот код корректируется для многих форм. Используйте на свой страх и риск.

const site_key = 'HEREYOURSITEKEY';

// This function retrieves the token from reCAPTCHA.
const retrieveToken = (form) => {
    // Mark the form as unresolved until the retrieval ends.
    form.unresolved = true;
    // Get the token.
    grecaptcha.execute(site_key, {
        action: form.action.substring(action.indexOf('?'), action.length).replace(/[^A-z\/_]/gi, '')
    }).then(token => {
        // Append the token to the form so it's sent along the other data.
        let child = document.createElement('input');
        child.setAttribute('type', 'hidden');
        child.setAttribute('name', '_recaptcha');
        child.setAttribute('value', token);
        form.appendChild(child);
        form.unresolved = false;
    });
};

// We will loop for each form in the document. You can add a "filter" method if you want.
Array.from(document.getElementByTagName('form'))
    .forEach(form => {
        // Mark it as unresolved from the beginning.
        form.unresolved = true;
        // Add an event listener that disables submission if the form is unresolved.
        form.addEventListener('submit', event => {
            if (form.unresolved) {
                event.preventDefault();
            }
        });
        // Resolve the token at startup.
        retrieveToken(form);
        // And retrieve a new token each 100 seconds. Bite me.
        setInterval(() => refreshToken(form), 100 * 1000);
    });
0 голосов
/ 26 мая 2020

Вы можете просто отключить отправку формы, пока токен не загрузится, и вместо этого показать какой-нибудь загрузчик. В обратном вызове then вы сохраняете токен в поле формы и разрешаете отправку формы (и скрываете загрузчик).

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

Таким образом, пользователь не столкнется с загрузчиком, если он не отправит форму тоже рано.

...