Work Laravel 5.3 Auth - Allow Username and Email

Laravel 5.3 Auth - Allow Username and Email

8th Sep, 2016 | Work

Alright, let us give the user a chance to sign into the system using either their email address or password - because well, we know how to do it and where they live!

Laravel ships with some authentication out of the box, but this only allows authentication by email address.
What we will do is add a username column to the database and then allow the user to use it interchangeably with their email address to log in.
While at it, we will also add an extra functionality that allows only the active users to log in. Why not.

  1. First step is to generate Laravel's auth scaffolding:
php artisan make:auth
  1. We need to edit the user table migration to add in relevant fields.
    We will get rid of the name column and replace it with first_name and then add last_name, username and active fields resulting in:
Schema::create('users', function (Blueprint $table) {
    $table->increments('id');
    $table->string('first_name');
    $table->string('last_name');
    $table->string('username')->unique();
    $table->string('email')->unique();
    $table->string('password');
    $table->boolean('active')->default(1);
    $table->rememberToken();
    $table->timestamps();
});    

That's all. Save and migrate to create the users table.

  1. Next we modify the registration form and add the new fields in: First Name, Last Name, Username:

  1. In line with this, the validation rules inside the RegisterController.php file that Laravel would have created for us have to be modified appropriately:
protected function validator(array $data)
{
    return Validator::make($data, [
        'first_name' => 'required|max:255',
        'last_name' => 'required|max:255',
        'username' => 'required|max:255|unique:users',
        'email' => 'required|email|max:255|unique:users',
        'password' => 'required|min:6|confirmed',
    ]);
} 
  1. And in the same class in the create method, add the new fields to the User::create call:
protected function create(array $data)
{
    return User::create([
        'first_name' => $data['first_name'],
        'last_name' => $data['last_name'],
        'username' => $data['username'],
        'email' => $data['email'],
        'password' => bcrypt($data['password']),
        'active' => 0,
    ]);
}
  1. We now need to add our new fields to the $fillable array in User.php which should now look like this:
    protected $fillable = ['first_name', 'last_name', 'username', 'email', 'password', 'active'];
  2. Now we are all set to register our users. The next step is handling logging in. Here, we want to allow the user to input either an email or a username in the username field. The first field in our login view should therefore look like:
<div class="form-group{{ $errors->has('username') ? ' has-error' : '' }}">
    <label for="username" class="col-md-4 control-label">Username or Email</label>
    <div class="col-md-6">
        <input id="username" type="text" class="form-control" name="username" value="{{ old('username') }}" autofocus>
        @if ($errors->has('username'))
            <span class="help-block">
                <strong>{{ $errors->first('username') }}</strong>
            </span>
        @endif
    </div>
</div>
  1. Let us now handle a login request. For this, we need to override the trait methods of the trait used in the LoginController.php
    The first method to override is the username method. Here we specify that the form field name to look for in our input is the username field (see the input field name in the view above).
    Add the following inside LoginController.php
public function username()
{
    return 'username';
}

The second method to override is the credentials method. Here we need to give the application a chance to determine which database table column to check against. We do this simply by quickly checking the user input to see if the username field has input that looks like an email. If so, we instruct it to use the email column otherwise, fall back to the username column.

/**
 * Override the trait method to allow login using either email or username
 * @param Request $request
 * @return array
 */
protected function credentials(Request $request)
{
    $usernameInput = trim($request->{$this->username()});
    $usernameColumn = filter_var($usernameInput, FILTER_VALIDATE_EMAIL) ? 'email' : $this->username();

    return [$usernameColumn => $usernameInput, 'password' => $request->password, 'active' => 1];
}

Notice that we are also adding an extra condition - the user must be active to successfully authenticate.

That's that. The user can now authenticate using either their email address or username and must also be active to go through.

Comments