Как добавить reCaptcha в форму Laravel

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

Нам просто нужно выполнить несколько простых шагов:

  • Зарегистрируйте свой сайт в reCaptcha и получите свой сайт и секретные ключи.
  • Добавьте ключи в окружение нашего приложения (файл .env в Laravel).
  • Включите ввод reCaptcha в форму нашей страницы.
  • Добавьте проверку reCaptcha в наш сервер (метод контроллера в Laravel).

Зарегистрируйте свой веб-сайт

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

После регистрации вы получите экран с вашими уникальными ключами и деталями интеграции клиент/сервер:

ключи

И это все, что нам нужно сделать со стороны reCaptcha. Теперь нам осталось только интегрировать его в наше приложение.

Добавить ключи в среду приложения

Нам нужно будет использовать наши клиентские и серверные ключи для вызова API reCaptcha как из передней, так и из задней части нашего приложения, поэтому, чтобы они были доступны во всем нашем приложении, мы можем добавить как переменные среды или, как мое приложение встроен в Laravel, я буду использовать файл .env, добавляя их в конец:

// .env file
GOOGLE_RECAPTCHA_KEY=YOUR_RECAPTCHA_SITE_KEY
GOOGLE_RECAPTCHA_SECRET=YOUR_RECAPTCHA_SECRET_KEY

В JavaScript вы можете загрузить их как переменные среды и получить к ним доступ с помощью process.env.VARIABLE_NAME .

Добавьте ввод reCaptcha в форму

Следующим шагом является включение флажка reCaptcha в нашу форму, используя два фрагмента кода из панели управления reCaptcha. Для этого примера у меня есть контактная форма с несколькими входными данными (имя, электронная почта и текст), которая отправляет всю полезную нагрузку через запрос POST на маршрут с именем «contact.send», который обрабатывается контроллером. Это выглядит так:

<form action="{{route('contact.send')}}" class="mb-3" method="post" enctype="multipart/form-data">
  {!! csrf_field() !!}
  <div class="form-row">
    <div class="form-group col-md-5">
      <label for="name" class="control-label">Name</label>
      <input name="name" class="form-control" type="text" id="name" value="{{old('name')}}">
    </div>
    <div class="form-group col-md-7">
      <label for="email" class="control-label">Email</label>
      <input name="email" class="form-control" type="email" id="email" value="{{old('email')}}">
    </div>
  </div>
  <div class="row">
      <div class="col-md-12 form-group">
       <label for="body" class="control-label">Message</label>
        <textarea name="body" id="body" class="form-control" cols="50" rows="10">{{old('body')}}</textarea>
   </div>
  </div>
  <div class="form-row mt-2">
  <div class="col-md-2 form-group text-right">
       <button type="submit" class="btn btn-info">Send</button>
   </div>
  </div>
</form>   

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

formaction="{{route('contact.send')}}"class="mb-3"method="post"enctype="multipart/form-data">

<form action="{{route('contact.send')}}" class="mb-3" method="post" enctype="multipart/form-data">
 {!! csrf_field() !!}    
    <div class="form-row">
        <div class="form-group col-md-5">  
        <label for="name" class="control-label">Name</label>
        <input name="name" class="form-control" type="text" id="name" value="{{old('name')}}">
        </div>  
        <div class="form-group col-md-7">  
        <label for="email" class="control-label">Email</label>
        <input name="email" class="form-control" type="email" id="email" value="{{old('email')}}">
        </div>  
    </div>    
    <div class="row">
        <div class="col-md-12 form-group">
        <label for="body" class="control-label">Message</label>
        <textarea name="body" id="body" class="form-control" cols="50" rows="10">{{old('body')}}</textarea> 
        </div>      
    </div>   
    @if(env('GOOGLE_RECAPTCHA_KEY'))    
    <div class="row"> 
        <div class="col-md-12 text-right"> 
        <div class="g-recaptcha" data-sitekey="{{env('GOOGLE_RECAPTCHA_KEY')}}"></div>
        </div>
    </div>
    @endif    
    <div class="form-row mt-2"> 
        <div class="col-md-2 form-group text-right">
        <button type="submit" class="btn btn-info">Send</button>
        </div> 
    </div>       
</form>
<script src='https://www.google.com/recaptcha/api.js'></script>

Обратите внимание, что предоставленный входной фрагмент включает ключ нашего сайта, жестко запрограммированный в нем, и, поскольку я включил его в файл .env, я заменил его ссылкой на переменную ;) На этом этапе мы должны увидеть ввод reCaptcha, когда мы загружаем нашу форму, но есть дополнительный шаг, который нам нужно сделать, прежде чем он действительно заработает.

Добавить проверку reCaptcha в админку

Чтобы понять изменения, которые нам нужно внести в наш контроллер, нам сначала нужно понять, что на самом деле происходит, когда пользователь нажимает на ввод reCaptcha.

  • На серверы Google отправляется запрос для проверки. Этот запрос содержит ключ нашего сайта, поэтому проверка связана с нашим сайтом.
  • Сервер Google отвечает уникальным идентификатором, который включен в нашу форму во входных данных с именем «g-recaptcha-response». Как только форма будет отправлена, мы сможем получить доступ к «g-recaptcha-response», чтобы получить идентификатор подтверждения.

В рамках обычных проверок на стороне сервера в нашем контроллере (проверьте, что все поля нашей формы заполнены и имеют правильный формат и т. д.), нам также нужно будет проверить, успешно ли Google подтвердил, что наш пользователь не является ботом отправив запрос POST в /recaptcha/api/siteverify Google, включая наш секретный ключ и идентификатор подтверждения из ввода «g-recaptcha-response», как указано в документации reCaptcha:

Интеграция с сервером reCaptcha

В PHP мы можем сделать это, используя функцию file_get_contents() для отправки запроса POST и функцию json_decode() для анализа ответа на объект JSON следующим образом:

// MessageController.php
/** 
    * Store a newly created resource in storage.
    *
    * @param  \Illuminate\Http\Request  $request
    * @return \Illuminate\Http\Response 
    */      
public function store(Request $request)   
{
    // validate all form fields are filled
    $request->validate([
    'name'=> 'required',      
    'email' => 'required|email',   
    'body' => 'required'
    ]);
    // check if reCaptcha has been validated by Google           
    $secret = env('GOOGLE_RECAPTCHA_SECRET'); 
    $captchaId = $request->input('g-recaptcha-response');
    //sends post request to the URL and tranforms response to JSON
    $responseCaptcha = json_decode(file_get_contents('https://www.google.com/recaptcha/api/siteverify?secret='.$secret.'&response='.$captchaId));
   if($responseCaptcha->success == true){
    // store the message in database
    $message =  new Message;
    $message->name = $request->name;
    $message->email = $request->email;
    $message->body = $request->body;  
    $message->save();
    // prepare notification    
    $request->session()->flash('message-for', 'message');                 
    $request->session()->flash('message-level', 'alert-success' );
    $request->session()->flash('message-content', 'Thanks for your message ' . $request->name . '. I will reply to you shortly');
    
    return back();    
   }else{  
    // send back error message  
    $request->session()->flash('message-for', 'message');                    
    $request->session()->flash('message-level', 'alert-warning' );    
    $request->session()->flash('message-content', 'Looks like you are a replicant. Sorry but I do not receive emails from non human entities :(');

    return back(); 
    }
}

В JavaScript вы можете использовать axios для отправки запроса POST, а затем JSON.parse() для преобразования ответа в объект.

Ответ на наш POST-запрос будет содержать свойство «success» со значением true/false, которое мы будем использовать для возврата сообщения об ошибке или, как в этом примере, для сохранения сообщения в нашей базе данных.

Заключение

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