Google reCaptcha in Laravel application

There are many options when it comes to captcha but most elegant solution is Google reCaptcha for sure. User is required only to click on checkbox and in some cases he needs to select few similar images and that's all.

I know that too often I bump on websites, which registration form has some weird characters in captcha field and I have to guess that combination few times cause I can't read anything there. So not to stress users I will be using the simplest captcha, Google reCaptcha.

I will work on same code as in previous tutorials Laravel 5 Social and Email Authentication and Laravel 5 client side validation with Parsley.js

All code from this tutorial is on Github.

Frontend implementation

I will first visit Google reCaptcha site https://www.google.com/recaptcha/ and register new site there. Good thing is that you can insert multiple domains, so same captcha placement can work on your development domain and production domain.

After registration of new site, I am redirected to captcha keys and quick guide how to implement widget.

reCaptcha Keys

I will store these keys into .env file.


RE_CAP_SITE=6LfAcwkTAAAAAIpZmjqpo-DQ4JWedQ2ywsw4T6qK
RE_CAP_SECRET=6LfAcwkTAAAAAJx5gxqn0S4jguJ-HrJmu7vfpUyI

I want this widget to appear after password confirmation filed, before Register button. Also I will include https://www.google.com/recaptcha/api.js in the footer section of the page.


<div class="g-recaptcha" data-sitekey="{{ env('RE_CAP_SITE') }}"></div>

<button class="btn btn-lg btn-primary btn-block register-btn" type="submit">Register</button>

With this I have completed frontend and it looks pretty good now.

Register form captcha field

Register form captcha field

Backend implementation

First I need to pull reCaptcha PHP package by adding "google/recaptcha": "~1.1"  to composer.json require section and doing update on composer dependencies. You may have already pulled this package if you followed first tutorial.

There are probably 10 different ways how I can code this, but I like reusable approach using traits. This way I can include captcha logic in multiple controllers with simple use statement without the need to inject dependencies.

This trait will be located in app/Traits/CaptchaTrait.php.


<?php namespace App\Traits;

use Input;
use ReCaptcha\ReCaptcha;

trait CaptchaTrait {

    public function captchaCheck()
    {

        $response = Input::get('g-recaptcha-response');
        $remoteip = $_SERVER['REMOTE_ADDR'];
        $secret   = env('RE_CAP_SECRET');

        $recaptcha = new ReCaptcha($secret);
        $resp = $recaptcha->verify($response, $remoteip);
        if ($resp->isSuccess()) {
            return 1;
        } else {
            return 0;
        }

    }

}

This method captchaCheck does everything, it takes input from user, sends request to Google and returns state. No need to pass any arguments in the method, simple $this->captchaCheck();  will do the job in the controller.

I am using built-in authentication controllers and I don't want to copy/paste any illuminate classes and re-implement them. So I found pretty elegant solution, I will only modify validator() method of RegisterController.

    /**
     * Get a validator for an incoming registration request.
     *
     * @param  array  $data
     * @return \Illuminate\Contracts\Validation\Validator
     */
    protected function validator(array $data)
    {

        $data['captcha'] = $this->captchaCheck();

        $validator = Validator::make($data,
            [
                'first_name'            => 'required',
                'last_name'             => 'required',
                'email'                 => 'required|email|unique:users',
                'password'              => 'required|min:6|max:20',
                'password_confirmation' => 'required|same:password',
                'g-recaptcha-response'  => 'required',
                'captcha'               => 'required|min:1'
            ],
            [
                'first_name.required'   => 'First Name is required',
                'last_name.required'    => 'Last Name is required',
                'email.required'        => 'Email is required',
                'email.email'           => 'Email is invalid',
                'password.required'     => 'Password is required',
                'password.min'          => 'Password needs to have at least 6 characters',
                'password.max'          => 'Password maximum length is 20 characters',
                'g-recaptcha-response.required' => 'Captcha is required',
                'captcha.min'           => 'Wrong captcha, please try again.'
            ]
        );

        return $validator;

    }

I am calling captchaCheck() from validator method and I am adding it's response to $data array, as it was a form field. In validation rule Laravel expects captcha to be min 1, and if captchaCheck() only returns 0 and 1, you see what will happen.

Don't forget to pull CaptchaTrait with use statement.

You can find full code used here on Github or you can test Live Demo here.

Lessons of this Series

Online computer science courses to jumpstart your future.
WP Engine Managed WordPress Hosting

Trending

Newsletter

Subscribe to our newsletter for good news, sent out every month.

Tags