Laravel 5.1 Auth CAPTCHA Example

Laravel Auth CAPTCHA Example demonstrates how to integrate Laravel CAPTCHA Package into login, register and reset password forms in a scenario where Laravel Auth is used to authenticate users to your application.

First Time Here?

Check the BotDetect Laravel 5.1 Captcha Quickstart for key integration steps.

Alongside the Captcha image, the user is provided with an input field to retype the displayed characters. Depending on if the Captcha code entered matches the displayed one or not, a message stating the validation result is shown on the form.

The simple code showing the message in this example would of course be replaced with useful form processing code in a real world scenario.

The default in Laravel 5.1 ships an example to authenticate users that is used Laravel Auth, but no captcha image is created. Here's what we started:

First, we need to configure database connection with entering connection details into the config/database.php file.

Next, we need to create users and password_resets tables -- using Migrations.

To create that tables, run the following command in your application's root directory:

Files for this ('bd-captcha-laravel-5.1-examples') example are:

The files are available for download as a part of the BotDetect Captcha Laravel integration package.

Routing – /app/Http/routes.php

// Authentication routes...
Route::get('auth/login', 'Auth\AuthController@getLogin');
Route::post('auth/login', 'Auth\AuthController@postLogin');
Route::get('auth/logout', 'Auth\AuthController@getLogout');

// Registration routes...
Route::get('auth/register', 'Auth\AuthController@getRegister');
Route::post('auth/register', 'Auth\AuthController@postRegister');

// Password routes...
Route::get('password/email', 'Auth\PasswordController@getEmail');
Route::post('password/email', 'Auth\PasswordController@postEmail');
Route::get('password/reset/{token}', 'Auth\PasswordController@getReset');
Route::post('password/reset/{token}', 'Auth\PasswordController@postReset');

In the code above we have registered the routes to handle the actions inside the AuthController and PasswordController.

Config – /config/captcha.php

<?php if (!class_exists('CaptchaConfiguration')) { return; }

// BotDetect PHP Captcha configuration options

return [
  // Captcha configuration for login page
  'LoginCaptcha' => [
    'UserInputID' => 'CaptchaCode',
    'CodeLength' => CaptchaRandomization::GetRandomCodeLength(4, 6),
    'ImageStyle' => [
      ImageStyle::Radar,
      ImageStyle::Collage,
      ImageStyle::Fingerprints,
    ],
  ],

  // Captcha configuration for register page
  'RegisterCaptcha' => [
    'UserInputID' => 'CaptchaCode',
    'CodeLength' => CaptchaRandomization::GetRandomCodeLength(4, 7),
    'CodeStyle' => CodeStyle::Alpha,
  ],

  // Captcha configuration for reset password page
  'ResetPasswordCaptcha' => [
    'UserInputID' => 'CaptchaCode',
    'CodeLength' => CaptchaRandomization::GetRandomCodeLength(3, 6),
    'CustomLightColor' => '#9966FF',
  ],

];

In order to use the Laravel CAPTCHA Package, we have declared Captcha configuration which will be used when showing Captcha image in login, register, and reset password views. Detailed description of this approach is available in a BotDetect Laravel 5.1 integration guide.

View – /resources/views/app.blade.php

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Laravel Auth Example</title>

  <!-- include the BotDetect layout stylesheet -->
  <link href="{{ captcha_layout_stylesheet_url() }}" type="text/css" rel="stylesheet">
</head>
<body>
  @yield('content')
</body>
</html>

The above code is defining a Blade Layout. The app view needs to add the required stylesheet of the library.

View – /resources/views/auth/login.blade.php

@extends('app')

@section('content')

<div>
  <h2>Login Form Validation BotDetect CAPTCHA Example</h2>

  @if (count($errors) > 0)
    <div class="alert alert-error">
      <strong>Whoops!</strong> There were some problems with your input.<br><br>
      <ul>
        @foreach ($errors->all() as $error)
          <li>{{ $error }}</li>
        @endforeach
      </ul>
    </div>
  @endif

  <form action="{{ URL::to('auth/login') }}" method="POST">
    {!! csrf_field() !!}

    <label>E-Mail Address</label>
    <input type="email" name="email" value="{{ old('email') }}" class="txt-input">

    <label>Password</label>
    <input type="password" name="password" class="txt-input">

    <!-- show captcha image html-->
    <label>Retype the characters from the picture</label>
    {!! captcha_image_html('LoginCaptcha') !!}
    <input type="text" id="CaptchaCode" name="CaptchaCode">

    <label><input type="checkbox" name="remember"> Remember Me</label>

    <br>
    <button type="submit">Login</button>

    <a href="{{ URL::to('password/email') }}">Forgot Your Password?</a> |
    <a href="{{ URL::to('auth/register') }}">Register</a>
  </form>

</div>

@endsection

The above code is to display authentication in a view, we show Captcha image by calling captcha_image_html() helper function. It is required to pass a captcha configuration key defined in config/captcha.php file (i.e. LoginCaptcha). We have also added Captcha Code input field to view.

View – /resources/views/auth/register.blade.php

@extends('app')

@section('content')

<div>
  <h2>Register Form Validation BotDetect CAPTCHA Example</h2>

  @if (count($errors) > 0)
    <div class="alert alert-error">
      <strong>Whoops!</strong> There were some problems with your input.<br><br>
      <ul>
        @foreach ($errors->all() as $error)
          <li>{{ $error }}</li>
        @endforeach
      </ul>
    </div>
  @endif

  <form action="{{ URL::to('auth/register') }}" method="POST">
    {!! csrf_field() !!}

    <label>Name</label>
    <input type="text" name="name" value="{{ old('name') }}" class="txt-input">

    <label>E-Mail Address</label>
    <input type="email" name="email" value="{{ old('email') }}" class="txt-input">

    <label>Password</label>
    <input type="password" name="password" class="txt-input">

    <label>Confirm Password</label>
    <input type="password" name="password_confirmation" class="txt-input">

    <!-- show captcha image html -->
    <label>Retype the characters from the picture</label>
    {!! captcha_image_html('RegisterCaptcha') !!}
    <input type="text" id="CaptchaCode" name="CaptchaCode">

    <br>
    <button type="submit">Register</button>

    <a href="{{ URL::to('auth/login') }}">Login</a>
  </form>

</div>
@endsection

The above code is to display authentication in a view, we show Captcha image by calling captcha_image_html() helper function. It is required to pass a captcha configuration key defined in config/captcha.php file (i.e. RegisterCaptcha). We have also added Captcha Code input field to view.

View – /resources/views/auth/password.blade.php

@extends('app')

@section('content')

<div>
  <h2>Reset Password Form Validation BotDetect CAPTCHA Example</h2>

  @if (session('status'))
    <div class="alert alert-success">
      {{ session('status') }}
    </div>
  @endif

  @if (count($errors) > 0)
    <div class="alert alert-error">
      <strong>Whoops!</strong> There were some problems with your input.<br><br>
      <ul>
        @foreach ($errors->all() as $error)
          <li>{{ $error }}</li>
        @endforeach
      </ul>
    </div>
  @endif

  <form action="{{ URL::to('password/email') }}" method="POST">
    {!! csrf_field() !!}

    <label>E-Mail Address</label>
    <input type="email" name="email" value="{{ old('email') }}" class="txt-input">

    <!-- show captcha image html -->
    <label>Retype the characters from the picture</label>
    {!! captcha_image_html('ResetPasswordCaptcha') !!}
    <input type="text" class="form-control" id="CaptchaCode" name="CaptchaCode">

    <br>
    <button type="submit">Send Password Reset Link</button>

  </form>
</div>
@endsection

The above code is to display authentication in a view, we show Captcha image by calling captcha_image_html() helper function. It is required to pass a captcha configuration key defined in config/captcha.php file (i.e. ResetPasswordCaptcha). We have also added Captcha Code input field to view.

Controller – /app/Http/Controllers/Auth/AuthController.php

<?php

namespace App\Http\Controllers\Auth;

use App\User;
use App\Http\Controllers\Controller;
use Validator;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;

class AuthController extends Controller
{
  /*
  |--------------------------------------------------------------------------
  | Registration & Login Controller
  |--------------------------------------------------------------------------
  |
  | This controller handles the registration of new users, as well as the
  | authentication of existing users. By default, this controller uses
  | a simple trait to add these behaviors. Why don't you explore it?
  |
  */

  use AuthenticatesAndRegistersUsers, ThrottlesLogins;

  /**
   * Create a new authentication controller instance.
   *
   * @return void
   */
  public function __construct()
  {
    $this->middleware('guest', ['except' => 'getLogout']);
  }

  /**
   * Get a validator for an incoming registration request.
   *
   * @param  array  $data
   * @return \Illuminate\Contracts\Validation\Validator
   */
  protected function validator(array $data)
  {
    return Validator::make($data, [
      'name' => 'required|max:255',
      'email' => 'required|email|max:255|unique:users',
      'password' => 'required|confirmed|min:6',
      'CaptchaCode' => 'required|valid_captcha'
    ]);
  }

  /**
   * Handle a login request to the application.
   *
   * @param  \Illuminate\Http\Request  $request
   * @return \Illuminate\Http\Response
   */
  public function postLogin(Request $request)
  {
    $this->validate($request, [
      $this->loginUsername() => 'required',
      'password' => 'required',
      'CaptchaCode' => 'required|valid_captcha',
    ]);

    // If the class is using the ThrottlesLogins trait, we can automatically throttle
    // the login attempts for this application. We'll key this by the username and
    // the IP address of the client making these requests into this application.
    $throttles = $this->isUsingThrottlesLoginsTrait();

    if ($throttles && $this->hasTooManyLoginAttempts($request)) {
      return $this->sendLockoutResponse($request);
    }

    $credentials = $this->getCredentials($request);

    if (Auth::attempt($credentials, $request->has('remember'))) {
      return $this->handleUserWasAuthenticated($request, $throttles);
    }

    // If the login attempt was unsuccessful we will increment the number of attempts
    // to login and redirect the user back to the login form. Of course, when this
    // user surpasses their maximum number of attempts they will get locked out.
    if ($throttles) {
      $this->incrementLoginAttempts($request);
    }

    return redirect($this->loginPath())
      ->withInput($request->only($this->loginUsername(), 'remember'))
      ->withErrors([
        $this->loginUsername() => $this->getFailedLoginMessage()
      ]);
  }
}

The Controller part of the example provides necessary helpers and data used by View, and adds the Captcha validation functionality as outlined in the BotDetect Laravel 5.1 integration guide.

The code above is that we are overridden the AuthenticatesAndRegistersUsers trait of the Laravel.

Method: validator()

On HTTP POST request (user submit), we validate the user's Captcha code input in the validator() method by using the valid_captcha validation rule that will be called in the postRegister() of RegistersUsers trait.

Method: postLogin()

On HTTP POST request (user submit), the postLogin() action executes and we check user's email and password using the Auth::attempt() and validate the user's Captcha code input by using the valid_captcha validation rule.

Controller – /app/Http/Controllers/Auth/PasswordController.php

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Foundation\Auth\ResetsPasswords;
use Illuminate\Mail\Message;
use Illuminate\Support\Facades\Password;

class PasswordController extends Controller
{
  /*
  |--------------------------------------------------------------------------
  | Password Reset Controller
  |--------------------------------------------------------------------------
  |
  | This controller is responsible for handling password reset requests
  | and uses a simple trait to include this behavior. You're free to
  | explore this trait and override any methods you wish to tweak.
  |
  */

  use ResetsPasswords;

  /**
   * Create a new password controller instance.
   *
   * @return void
   */
  public function __construct()
  {
    $this->middleware('guest');
  }

  /**
   * Send a reset link to the given user.
   *
   * @param  \Illuminate\Http\Request  $request
   * @return \Illuminate\Http\Response
   */
  public function postEmail(Request $request)
  {
    $this->validate($request, [
      'email' => 'required|email',
      'CaptchaCode' => 'required|valid_captcha'
    ]);

    $response = Password::sendResetLink($request->only('email'), function (Message $message) {
      $message->subject($this->getEmailSubject());
    });

    switch ($response) {
      case Password::RESET_LINK_SENT:
        return redirect()->back()->with('status', trans($response));

      case Password::INVALID_USER:
        return redirect()->back()->withErrors(['email' => trans($response)]);
    }
  }
}

The Controller part of the example provides necessary helpers and data used by View, and adds the Captcha validation functionality as outlined in the BotDetect Laravel 5.1 integration guide.

The code above is that we are overridden the ResetsPasswords trait of the Laravel.

On HTTP POST request (user submit), the postEmail() action executes and we validate the user's Captcha code input by using the valid_captcha validation rule.