Laravel 4.2 Auth CAPTCHA Example

Laravel Auth CAPTCHA Example demonstrates how to integrate BotDetect PHP Captcha into login and register forms in a scenario where Laravel Auth is used to authenticate users to your application.

First Time Here?

Check the BotDetect Laravel 4.2 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.

We have used Forms & HTML to generate a form, Validation class to validate input fields data, and Blade Templating.

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

Next, we need to create users table -- using Migrations. We have prepared a create-users-table migration which is located at: app/database/migrations/

To create users table, run the following command in your application's root directory:

Files for this example are:

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

Routing – /app/routes.php

Route::controller('users', 'UsersController');

In the code above we use the Implicit Controllers to define a single route which will handle every user action in the UsersController.

Config – /app/config/captcha.php

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

// BotDetect PHP Captcha configuration options

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

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

);

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

View – /app/views/layouts/master.blade.php

<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <title>Laravel Authentication</title>
  {{ HTML::style('css/bootstrap.min.css') }}
  
  <!-- include the BotDetect layout stylesheet -->
  {{ HTML::style(captcha_layout_stylesheet_url()) }}

  <style type="text/css">
    body { padding: 70px 0 }
    .container{ width: 980px !important }
    .error { color: red }
  </style>
</head>
<body>
  <nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
   <div class="container">
    <div class="navbar-header">
     <a class="navbar-brand" href="#">BotDetect Captcha</a>
    </div>
    <div id="navbar" class="navbar-collapse collapse">
     <ul class="nav navbar-nav navbar-right">
      <!-- Determining if a user is authenticated --> 
      @if (Auth::check())
         <li>{{ HTML::link('users/logout', 'Logout') }}</li>   
      @else
        <li>{{ HTML::link('users/register', 'Register') }}</li>   
        <li>{{ HTML::link('users/login', 'Login') }}</li>  
      @endif
     </ul>
    </div><!--/.nav-collapse -->
   </div>
  </nav>

   <div class="container">
     @yield('content')
  </div>
</body>
</html>

The above code is defining a Blade Layout. We have added required stylesheet using the HTML::style() method. Checking whether the user is logged in or not we did with Auth::check() method.

View – /app/views/users/login.blade.php

@extends('layouts.master')

@section('content')

  <h2>Login</h2><hr>

  @if (Session::has('status'))
   <div class="alert alert-success">
    {{ Session::get('status') }}
   </div>
  @endif

  @if (count($errors) > 0)
   <div class="alert alert-danger">
    <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::open(array('url' => 'users/login')) }}

  <div class="form-group">
    {{ Form::label('inputEmail', 'Email') }}
    {{ Form::text('email', Input::old('email'), array(
        'id' => 'inputEmail',
        'class' => 'form-control'
      ))
    }}
  </div>

  <div class="form-group">
    {{ Form::label('inputPassword', 'Password') }}

    {{ Form::password('password', array(
        'id' => 'inputPassword',
        'class' => 'form-control'
      ))  
    }}
  </div>

  <div class="form-group">
    <!-- Captcha image html-->
    {{ captcha_image_html('LoginCaptcha') }}
  </div>

  <div class="row">
    <div class="form-group col-sm-4">
      {{ Form::label('CaptchaCode', 'Retype the characters from the picture') }}

      <!-- Captcha code user input textbox -->
      {{ Form::text('CaptchaCode', null, array(
          'id' => 'CaptchaCode',
          'class' => 'form-control'
        ))
      }}
    </div>
  </div>

  <div class="checkbox">
    <label>{{ Form::checkbox('remember_me', null) }} Remember me</label>
  </div>

  {{ Form::submit('Login', array('class' => 'btn btn-primary')) }}    
{{ Form::close() }}

@stop

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 app/config/captcha.php file (i.e. LoginCaptcha). We have also added Captcha Code input field to view. This Captcha Code input will be checked in the postLogin() action later.

View – /app/views/users/register.blade.php

@extends('layouts.master')

@section('content')

  <h2>Register now</h2><hr>

  @if (Session::has('status'))
   <div class="alert alert-success">
    {{ Session::get('status') }}
   </div>
  @endif

  @if (count($errors) > 0)
   <div class="alert alert-danger">
    <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::open(array('url' => 'users/register')) }}

  <div class="form-group">
    {{ Form::label('inputName', 'Name') }}
    {{ Form::text('name', Input::old('name'), array(
        'id' => 'inputName',
        'class' => 'form-control'
      ))
    }}
  </div>

  <div class="form-group">
    {{ Form::label('inputEmail', 'Email') }}
    {{ Form::text('email', Input::old('email'), array(
        'id' => 'inputEmail',
        'class' => 'form-control'
      ))
    }}
  </div>

  <div class="form-group">
    {{ Form::label('inputPassword', 'Password') }}

    {{ Form::password('password', array(
        'id' => 'inputPassword',
        'class' => 'form-control'
      ))  
    }}
  </div>

  <div class="form-group">
    {{ Form::label('inputPasswordConfirmation', 'Confirm Password') }}

    {{ Form::password('password_confirmation', array(
        'id' => 'inputPasswordConfirmation',
        'class' => 'form-control'
      ))  
    }}
  </div>

  <div class="form-group">
    <!-- Captcha image html-->
    {{ captcha_image_html('RegisterCaptcha') }}
  </div>

  <div class="row">
    <div class="form-group col-sm-4">
      {{ Form::label('CaptchaCode', 'Retype the characters from the picture') }}

      <!-- Captcha code user input textbox -->
      {{ Form::text('CaptchaCode', null, array(
          'id' => 'CaptchaCode',
          'class' => 'form-control'
        ))
      }}
    </div>
  </div>

  {{ Form::submit('Register', array('class' => 'btn btn-primary')) }}     
{{ Form::close() }}

@stop

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 app/config/captcha.php file (i.e. RegisterCaptcha). We have also added Captcha Code input field to view. This Captcha Code input will be checked in the postRegister() action later.

View – /app/views/users/dashboard.blade.php

@extends('layouts.master')

@section('content')
  <h2>Dashboard</h2><hr>
  Welcome <strong>{{ Auth::user()->name }}</strong>. You have logged in your system.
@stop

The code above displays the logged-in user's name using the Auth::user() method.

Controller – /app/controllers/UsersController.php

<?php

class UsersController extends BaseController {

  protected $layout = 'layouts.master';

  public function getRegister() {
    $this->layout->content = View::make('users.register');
  }

  public function postRegister() {

    $validator = Validator::make(Input::all(), array(
        'name' => array('required', 'alpha', 'min:5'),
        'email'    => array('required', 'email', 'unique:users'),
        'password' => array('required', 'between:6,30', 'confirmed'),
        'password_confirmation' => array('required', 'between:6,30'),
        'CaptchaCode' => array('required', 'valid_captcha')
      )
    );

    if ($validator->fails()) 
    {
      return Redirect::to('users/register')
              ->withInput()
              ->withErrors($validator->errors());
    }

    // Captcha validation passed
    // Save new user
    $user = new User;
    $user->name = Input::get('name');
    $user->email = Input::get('email');
    $user->password = Hash::make(Input::get('password'));
    $user->save();

    return Redirect::to('users/register')
              ->with('status', 'Thank you. You have successfully registerd.');
  }

  public function getLogin() {
    $this->layout->content = View::make('users.login');                                        
  }

  public function postLogin() {

    // validate the user-entered Captcha code when the form is submitted
    $code = Input::get('CaptchaCode');
    $isHuman = captcha_validate($code);

    $rememberMe = (Input::get('remember_me') == 'on') ? true : false;
    $errorMessages = array();

    if ($isHuman) 
    {
      if (Auth::attempt(array('email' => Input::get('email'), 'password' => Input::get('password')), $rememberMe)) 
      {
        return Redirect::to('users/dashboard');
      }
      else
      {
        $errorMessages = array('email' => 'The email or password you entered is incorrect, please try again.');
      }
    }
    else
    {
      $errorMessages = ['CaptchaCode' => 'Wrong code. Try again please.'];
    }

    return Redirect::to('users/login')
            ->withInput(Input::except('password'))
            ->withErrors($errorMessages);
  }

  public function getDashboard() {
    $this->layout->content = View::make('users.dashboard');
  }

  public function getLogout() {
    Auth::logout();
    return Redirect::to('users/login');
  }
  
}

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 4.2 integration guide.

Method: postRegister()

On HTTP POST request (user submit), the postRegister() action executes and we validate user entered data using the Validation class and validate Captcha Code by using the valid_captcha validation rule.

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 Captcha Code with the captcha_validate() helper function.

Filters – /app/filters.php

Route::filter('auth', function()
{
  if (Auth::guest())
  {
    if (Request::ajax())
    {
      return Response::make('Unauthorized', 401);
    }
    else
    {
      // Redirect to the users/login page 
      return Redirect::guest('users/login');
    }
  }
});

In code above we have modified the auth filter to redirect all non-authenticated users to users/login page.