reCaptcha v2 для Laravel
21.02.2021
107

reCaptcha v2 для Laravel

Для защиты форм от спама полезно добавлять всем надоевшую reCaptcha от Google, которая существенно позволяет сократить количество сообщений от ботов на вашем сайте.


В этой статье рассмотрим шаги по интеграции reCaptcha v2 в проект на Laravel.


Проект в GitHub: https://github.com/zetrider/Laravel-reCatpcha 


Настройка проекта:

  1. Добавляем новый проект в Google ReCaptcha https://www.google.com/recaptcha/admin/create 
  2. Заполняем форму

    1. Ярлык - назвние проекта
    2. Тип reCAPTCHA - в текущей статье рассматривается reCAPTCHA v2, Флажок "Я не робот"
    3. Домены - указываем свой домен, жмем слева +
    4. Принимаем условие, жмем кнопку "Отправить"
  3. На следующем экране получаем ключи для работы в reCaptcha


Настройка Laravel для reCaptcha:

  1. В файл проекта .env добавляем ключи из предыдущего шага
    GOOGLE_RECAPTCHA_ID=
    GOOGLE_RECAPTCHA_SECRET=
  2. В файл /config/services.php дополним массив кодом:
    'google' => [
        'recaptcha_id' => env('GOOGLE_RECAPTCHA_ID'),
        'recaptcha_secret' => env('GOOGLE_RECAPTCHA_SECRET'),
    ],
    
  3. Добавим Action для логики верификации reCaptcha, создадим файл /app/Actions/ReCaptchaAction.php разместив в нем код:
    namespace App\Actions;
    
    use GuzzleHttp\Client;
    
    class ReCaptchaAction
    {
        /**
         * @var string
         */
        private $key;
    
        /**
         * @var string
         */
        private $endpoint;
    
        /**
         * @var Client
         */
        private $client;
    
        public function __construct()
        {
            $this->setKey();
            $this->setEndpoint();
            $this->setClient();
        }
    
        /**
         * @return $this
         */
        public function setKey(): ReCaptchaAction
        {
            $this->key = config('services.google.recaptcha_secret');
    
            return $this;
        }
    
        /**
         * @return string
         */
        public function getKey(): string
        {
            return $this->key;
        }
    
        /**
         * @return $this
         */
        public function setEndpoint(): ReCaptchaAction
        {
            $this->endpoint = 'https://google.com/recaptcha/api/';
    
            return $this;
        }
    
        /**
         * @return string
         */
        public function getEndpoint(): string
        {
            return $this->endpoint;
        }
    
        /**
         * @return $this
         */
        public function setClient(): ReCaptchaAction
        {
            $this->client = new Client([
                'base_uri' => $this->getEndpoint(),
            ]);
    
            return $this;
        }
    
        /**
         * @return Client
         */
        public function getClient(): Client
        {
            return $this->client;
        }
    
        /**
         * @param string $value
         * @return array
         * @throws \GuzzleHttp\Exception\GuzzleException
         */
        public function verify($value): array
        {
            $params = $this->requestParams($value);
            $response = $this->getClient()->post('siteverify', [
                'query' => $params
            ]);
    
            $data = json_decode($response->getBody(), true);
    
            if (!is_array($data)) {
                $data = [];
            }
    
            return $data;
        }
    
        /**
         * @param string $value
         * @return array
         */
        private function requestParams(string $value): array
        {
            return [
                'secret' => config('services.google.recaptcha_secret'),
                'response' => $value
            ];
        }
    }
    


  4.  Выполним команду "php artisan make:rule ReCaptchaRule" или создадим вручную файл в проекте /app/Rules/ReCaptchaRule.php разместим код класса:
    namespace App\Rules;
    
    use App\Actions\ReCaptchaAction;
    use Illuminate\Contracts\Validation\Rule;
    
    class ReCaptchaRule implements Rule
    {
        /**
         * Determine if the validation rule passes.
         *
         * @param string $attribute
         * @param mixed $value
         * @return bool
         */
        public function passes($attribute, $value)
        {
            $success = false;
            $verify = (new ReCaptchaAction())->verify($value);
    
            if (array_key_exists('success', $verify)) {
                $success = $verify['success'];
            }
    
            return $success;
        }
    
        /**
         * Get the validation error message.
         *
         * @return string
         */
        public function message()
        {
            return __('Проверка reCaptcha прошла с ошибкой.');
        }
    }
    


Проверяем работу валидатор:

  1. Создаем валидацию командой php artisan make:request FeedbackRequest или создаем файл вручную /app/Http/Requests/FeedbackRequest.php разместив в нем код
    namespace App\Http\Requests;
    
    use App\Rules\ReCaptchaRule;
    use Illuminate\Foundation\Http\FormRequest;
    
    class FeedbackRequest extends FormRequest
    {
        /**
         * Determine if the user is authorized to make this request.
         *
         * @return bool
         */
        public function authorize()
        {
            return true;
        }
    
        /**
         * Get the validation rules that apply to the request.
         *
         * @return array
         */
        public function rules()
        {
            return [
                'message' => [
                    'required',
                    'string',
                ],
                'g-recaptcha-response' => ['required', new ReCaptchaRule]
            ];
        }
    }
    
  2. Создаем контроллер, php artisan make:controller FeedbackController или вручную /app/Http/Controllers/FeedbackController.php разместив в нем код:
    namespace App\Http\Controllers;
    
    use App\Http\Requests\FeedbackRequest;
    use Illuminate\Http\Request;
    
    class FeedbackController extends Controller
    {
        /**
         * Index
         *
         * @return \Illuminate\Http\Response
         */
        public function index()
        {
            return view('feedback');
        }
    
        /**
         * Store
         *
         * @param  \App\Http\Requests\FeedbackRequest $request
         * @return \Illuminate\Http\Response
         */
        public function store(FeedbackRequest $request)
        {
            dd($request->all());
        }
    }
    
    
  3. Добавим тестовый blade файл /app/resources/views/feedback.blade.php с простой формой:
  4. При использовании js для отправки данных, лучше сбрасывать каптчу, так как повторная валидация не пропустит запрос:
    grecaptcha.reset()
  5. Добавим для тестов роуты в /routes/web.php
    
    Route::get('feedback', 'App\Http\Controllers\FeedbackController@index')->name('feedback.index');
    Route::post('feedback', 'App\Http\Controllers\FeedbackController@store')->name('feedback.store');
    


Подобным способом можно обеспечить защиту формы от большинства ботов для защиты публичных форм в проекте от спама.

Источник: ZetRider
Laravel Nova - Как вывести в трендах сумму за период
24.02.2021
81
Laravel Nova - Как вывести в трендах сумму за период

В Laravel Nova удобно отображать метрики через тренды. Создавая периоды можно получить информацию например о новых пользователях в системе. В одном пр...

Читать →
Bash деплой - аналог Envoyer
24.02.2021
100
Bash деплой - аналог Envoyer

Для быстрого деплоя личных или простых проектов можно использовать сервисы подобные Envoyer.io о котором писал ранее или написать свой велосипед на ba...

Читать →
Envoyer - деплой без задержек
26.01.2021
97
Envoyer - деплой без задержек

Zero Downtime PHP Deployment - способ развернуть сервис незаметно для посетителей.Во времена развития CI/CD на фоне инструментов GitLab, BitBucket, Tr...

Читать →