Advanced Laravel - User Authentication

Posted on - Last Modified on

User management is an important part of any Web application project. The Laravel framework provides a nice and sleek way of managing users and login sessions. In this article, I will present a way to handle user login and login data with Laravel. The application that I am extending is the one created for the Web Development Using Laravel article.

The source code can be found on GitHub in the laravel_web repository.

Data Layer

It doesn't matter what Web framework we use; user-related data has to be stored somewhere. In this case, I am using MySQL to create a new table, which will hold the user data. I'll use artisan to create the default database migration by running this from the command line:

     php artisan migrate:make create_appusers_table

This will create a new file under the laravel/app/database/migrations folder, in my case this was 2015_03_29_174512_create_appusers_table.php. Update the file content to:

        public function up()
	{
		if(!Schema::hasTable('appusers')) 
		{
			Schema::create('appusers', function(Blueprint $table)
			{
				$table->increments('id');
				$table->string('name', 150);
				$table->string('username', 150);				
				$table->string('email', 150);
				$table->string('password', 128);
				$table->string('remember_token',100)->nullable();
				$table->timestamps();				
			});
		}
	}

I called the table that will hold user information appusers. In the up() function I check if the table does not exist then I create it, storing the name, email address, username and password. The id is the unique identifier for each user, this is an auto-incremented value.

The remember_token field is special – this was added in an update of Laravel4 and it helps to increase the security of user sessions. Each time the user logs into the application, this field is updated with a new token so that it becomes invalid after each session. In order to use this feature, I need to update the User.php file under app/models and make the following changes:

        protected $table = 'appusers';
	public function getRememberToken()
	{
	    return $this->remember_token;
	}

	public function setRememberToken($value)
	{
	    $this->remember_token = $value;
	}

	public function getRememberTokenName()
	{
	    return 'remember_token';
	}

Of course, if it's in the database I would have named my token holder field temporary_user_token, then in the getRememberTokenName() I would need to return that name.

After doing these, I define some sample users for testing purposes. For this I create a new seeder file under app/database/seeds called AppusersTableSeeder.php:

class AppusersTableSeeder extends Seeder
{
	public function run()
	{
	    DB::table('appusers')->delete();
	    User::create(array(
	        'name'     => 'John Doe',
	        'username' => 'johndoe',
	        'email'    => 'john@doe.com',
	        'password' => Hash::make('laravel'),
	    ));

	    User::create(array(
	        'name'     => 'Jane Doe',
	        'username' => 'janedoe',
	        'email'    => 'jane@doe.com',
	        'password' => Hash::make('laravel1234'),
	    ));
	}
}

This only creates two users and inserts the entries in the appusers table.

After these are all set up, I run the migrations plus the seeds:

        php artisan migrate
	php artisan db:seed

At this point, the new table appusers is created and it has 2 rows (JSON export):

[{"id":"1","name":"John Doe","username":"johndoe","email":"john@doe.com", "password":"$2y$10$bqdWyZHMDBq6HTI1mPk\/CeieMlEGNQS9\/09DmB8olv5X5omMV4J4e","remember_token":"vs5uBh5o9kY1P7TzfmS7DnHvnp5l18oVL7yjPT7msUuv5eKe7jpa7jE7S3p3","created_at":"2015-03-29 17:55:44"
,"updated_at":"2015-03-29 19:36:45"}, 

{"id":"2","name":"Jane Doe","username":"janedoe","email":"jane@doe.com", "password":"$2y$10$uFas.EmKrnnoLK03e5r3ye0KtAtqTcV4ML3srvbnTIckvhRkZG7v2", "remember_token":"UdVZ3GPhCsJKhkIDdCvYairC4Flx38o8yGixMiTfs7Gk2k2j8ZLRZG9eMlvF","created_at":"2015-03-29 17:55:44"
,"updated_at":"2015-03-29 19:14:08"}]

The Controller

I create a new controller called LoginController under the app/controllers folder. I define three methods: getLogin() returns the login view, logout() handles the logout requests of the users and processLogin() handles the login request sent by the user.

        public function getLogin() 
	{
		return View::make('login');
	}

	public function logout() 
	{
		Auth::logout();
		return Redirect::to('login');
	}
	public function processLogin() 
	{
		$rules = array('email' => 'required|email',
				  'password' => 'required|alphaNum|min:5' );

		$validator = Validator::make(Input::all(), $rules);

		if ($validator->fails()) {
			return Redirect::to('login')
					->withErrors($validator)
					->withInput(Input::except('password'));
		} else {
			$userdata = array('email' => Input::get('email'),'password'  => Input::get('password'));
			if (Auth::attempt($userdata)) {
        			return Redirect::to('/');
    			} else {        
        			return Redirect::to('login');
    			}
		}
	}

In the processLogin() I set up a validation for the incoming data: email and password fields are required, and the password has to be an alphanumeric value that has to be at least 5 characters long. If the incoming request passes validation, I check if the user is valid with Auth::attempt() Laravel method. If the user is valid I redirect the user to the main page. Otherwise the request bounces back to the login page.

The routing setup needs to be updated to handle the login and logout requests. For that, I need to do the following modification in app/routes.php:

Route::get('/login', array('as'=> 'login', 'uses' => 'LoginController@getLogin'));
Route::post('/logout', array('as'=> 'logout', 'uses' => 'LoginController@logout'));
Route::post('/login', array('as' => 'login', 'uses' => 'LoginController@processLogin'));

The login has two routings – GET for returning the login form, pointing to getLogin() method and POST for handling when the user presses the Sign in button on the page:

login page

After a successful login, the user is redirected to the main page (I added the Logout button for handling the logout request that is also a POST request).

user logged in

Creating the Forms

Laravel uses blade as a template engine, I need to define the login form using that. The application uses bootstrap to build the UI, so I use CSS from there.

I add the following code to the app/views/login.blade.php:

{{ Form::open(array('url' => 'login', 'method'=>'post' ,'class'=>'form-horizontal')) }}
@foreach ($errors->all('<div class="alert alert-danger" role="alert">:message</div>') as $message)
	{{$message}}
@endforeach
      <div class="form-group">	
      {{ Form::label('email', 'Email Address', array('class'=>'col-sm-2 control-label')) }}
 		<div class="col-sm-3">
    		{{ Form::text('email', Input::old('email'), array('placeholder'=> 'user@example.com', 'class'=>'form-control'))}}
		</div>
  	</div>
      <div class="form-group">	
	   {{ Form::label('password', 'Password', array('class'=>'col-sm-2 control-label')) }}
          <div class="col-sm-3">
    	     {{ Form::password('password', array('class'=>'form-control')) }}
           </div>
  		</div>
  		<div class="form-group">
  		 <div class="col-sm-5">	
	        {{ Form::submit('Sign in', array('class'=>'btn btn-primary btn-block '))}}
	        </div>
  		</div>
    {{ Form::close() }}

I am using Form methods from Laravel to create the forms. In the first line, I open the form and specify the method (POST) and the url (login), which is invoked once the Sign in button is pressed. Then I list all the errors which are sent from Laravel (for example in case of an incorrect username and password) the following errors will be shown:

I create labels and text inputs for email and password and specify the styling. At the end I close the form using the Form::close() method. This is important, so please make sure that you always include it.

error

The Logout button is inside a form too, and does a post request which is handled by the logout method of the LoginController.

@if (Auth::check())
    {{ Form::open(array('url' => 'logout', 'method'=>'post' ,'class'=>'navbar-form navbar-right')) }}
        <button type="submit" class="btn btn-success">Logout</button>
    {{ Form::close() }}
@endif

It is important to note that I only display the Logout button if the user is logged in, I can use the Auth::check() method from Laravel to see if we have a valid user logged in.

User's login information is sensitive data and Laravel provides a standard API to manage it, but at the same time, it allows developers to create custom structures for holding user data.

Posted 31 March, 2015

Greg Bogdan

Software Engineer, Blogger, Tech Enthusiast

I am a Software Engineer with over 7 years of experience in different domains(ERP, Financial Products and Alerting Systems). My main expertise is .NET, Java, Python and JavaScript. I like technical writing and have good experience in creating tutorials and how to technical articles. I am passionate about technology and I love what I do and I always intend to 100% fulfill the project which I am ...

Next Article

Tips on Reducing Your Website’s Bounce Rate