Как добавить 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:
В 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, но аналогичным образом можно интегрировать различные типы. Надеюсь, вы найдете эту статью полезной :)