reCaptcha v2 для Laravel
21.02.2021
610

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
Вывод Builder SQL запроса с переданными значениями
09.11.2021
57
Вывод Builder SQL запроса с переданными значениями

Для анализа SQL запросов в Laravel из коробки присутствует метод toSql класса \Illuminate\Database\Eloquent\Builder. Но данный метод возвращает п...

Читать →
Laravel Nova: Множественные поля
28.10.2021
68
Laravel Nova: Множественные поля

Множественные поля для Laravel Nova основаны на хранении данных в json формате свойства модели.GitHubУстановка:composer require zetrider/nova-inputs-f...

Читать →
Тестирование и отладка роутов Laravel при помощи DebugBar
09.10.2021
107
Тестирование и отладка роутов Laravel при помощи DebugBar

Для тестирования роутов на наличие дубликата sql запросов, потребления памяти или времени загрузки можно использовать удобный интерфейс laravel-debugb...

Читать →