Все современные пользователи интернета неоднократно сталкивались с различными captcha. Если говорить кратко, то это аббревиатура от «Completely Automatic Public Turing Test to Tell Computers and Humans Apart». Человек просто и быстро может решить задачу по распознаванию искаженных или пересекающих друг друга букв или цифр. Для того, чтобы подтвердить, что человек действительно человек, а не спам бот.
С течением времени капчи эволюционировали. Простейшие из них предлагают человеку выполнить несложную математическую операцию или ответить на вопрос. Более сложные – распознать слово или слова на изображении. В последние годы практически везде мы встречаем captcha от Google — reCAPTCHA. Есть и так называемая «невидимая» (invisible) reCAPTCHA. Она сама определяет, когда «проверить» пользователя (обычно это распознавание похожих изображений на заданную тему) и не портит внешний вид вашей формы.
Невидимая капча на фронте и как написать обработчик на бекэнде используя Drupal
Для Drupal 8 есть готовый модуль reCAPTCHA, далее мы рассмотрим самостоятельную работу с каптчей, без использования этого модуля.
Процесс работы капчи следующий: со стороны фронта получаем токен, отправляем этот токен на бекэнд. Бекэнд делает POST запрос к Google API с данными: IP-юзера и токен полученный с фронта.
Front-end
Добавляем скрипт капчи (в документации отмечено, что протокол обязательно https):
<script src="https://www.google.com/recaptcha/api.js?hl=ru" async defer></script>
Параметр ?hl=ru нужен чтобы русифицировать капчу.
Внутри формы добавляем разметку капчи:
<div class="g-recaptcha"
data-sitekey="sitekey"
data-callback="onSubmit"
data-size="invisible">
</div>
- data-sitekey — публичный код капчи для сайта;
- data-callback = "onSubmit" — функция, которая вызывается после получения токена (имеет один входной параметр token).
При отправке формы мы должны вызвать grecaptcha.execute(); (например, в onSubmit). При этом дополнительных действий по встраиванию токена в форму делать не надо, капча все сделает за нас. При сабмите формы у нас появится параметр g-recaptcha-response, в котором содержится токен капчи для проверки на сервере.
Возможен вариант без прямого вызова grecaptcha.execute(), тогда параметры data-sitekey и data-callback прописываются прямо на кнопке сабмита формы. Первый вариант — более универсален.
Back-end
Пример обработки на Drupal 8 (обработка данных из POST запроса):
use GuzzleHttp\Exception\RequestException;
...
// Get ReCaptcha token from front end
$data['google_captcha_token'] = '';
$data['google_captcha_token'] = \Drupal::request()->request->get('g-recaptcha-response');
// dev:
\Drupal::logger('my_module')->notice($data['google_captcha_token']);
$user_ip = \Drupal::request()->getClientIp();
$secret_key = '<GOOGLE_SECRET_KEY>';
// Check (true - spam)
$spam = $this->checkSpamRecaptcha($secret_key, $user_ip, $data['google_captcha_token']);
if (!$spam) {
// ...do stuff here
}
else {
// ...spamer!
}
Не забудьте подставить в $secret_key ваше значения ключа. И удалить или изменить строку с логированием.
Функция проверки:
/**
* Check Google API for ReCaptcha information
*
* POST (application/x-www-form-urlencoded) request to
* https://www.google.com/recaptcha/api/siteverify
*
* @param $secret_key
* ReCaptcha secret key from Google recaptcha service
*
* @param $remoteip
* User ip
*
* @param $g_recaptcha_response
* Special token from front-end
*
* @return bool
* TRUE - spam, FALSE - human and good man
*/
public function checkSpamRecaptcha($secret_key, $remoteip, $g_recaptcha_response) {
$spamer = true;
$client = \Drupal::httpClient();
try {
// Sending application/x-www-form-urlencoded POST requests requires that you
// specify the POST fields as an array in the form_params request options.
// http://docs.guzzlephp.org/en/latest/quickstart.html#sending-requests
$body = [
'form_params' => [
'secret' => $secret_key,
'response' => $g_recaptcha_response,
'remoteip' => $remoteip,
],
];
$response = $client->request('POST', 'https://www.google.com/recaptcha/api/siteverify', $body);
$data = $response->getBody();
$recaptcha = json_decode($data);
if ($recaptcha->success) {
$spamer = false;
}
}
catch (RequestException $e) {
\Drupal::logger('my_module')->notice($e->getMessage());
}
return $spamer;
}