Logging in and handling validation

Published on March 24th, 2018

Modifying our authentication

We've had our authentication code for a while now, but we need to make a little change in our app/Http/Controllers/Auth/LoginController.php class.

app/Http/Controllers/Auth/LoginController.php
--- a/app/Http/Controllers/Auth/LoginController.php
+++ b/app/Http/Controllers/Auth/LoginController.php
@@ -7,17 +7,6 @@ use Illuminate\Foundation\Auth\AuthenticatesUsers;

 class LoginController extends Controller
 {
-    /*
-    |--------------------------------------------------------------------------
-    | Login Controller
-    |--------------------------------------------------------------------------
-    |
-    | This controller handles authenticating users for the application and
-    | redirecting them to your home screen. The controller uses a trait
-    | to conveniently provide its functionality to your applications.
-    |
-    */
-
     use AuthenticatesUsers;

     /**
@@ -25,7 +14,7 @@ class LoginController extends Controller
      *
      * @var string
      */
-    protected $redirectTo = '/home';
+    protected $redirectTo = '/services';

Here we are telling Laravel where to redirect a user after they have logged in. In this case, we are specifying the /services route we created in the previous episode. We also removed some comments we won't be needing.

We have our authentication controllers, now let’s add our routes.

We already have a route to show the login page within routes/web.php. Now it’s time to start using the controllers we have inside the app\Http\Controllers\Auth folder. For now, we will only activate the routes to login and logout a user. If you have any experience with Laravel, you know this can be achieved by simply adding Auth::routes() in your routes file. This registers a few other routes we don’t need at the moment like for registration, password resets, etc. In our case, we will register the routes we want manually. We can do this as follows:

routes/web.php
--- a/routes/web.php
+++ b/routes/web.php
 <?php

-Route::get('/login', function () {
-    return view('login');
-})->name('login');
+/*
+|--------------------------------------------------------------------------
+| Authentication
+|--------------------------------------------------------------------------
+|
+*/
+
+Route::get('/login', 'Auth\LoginController@showLoginForm')->name('login');
+Route::post('/login', 'Auth\LoginController@login');
+Route::get('/logout', 'Auth\LoginController@logout')->name('logout');

Update the ServicesController

At the moment, we are specifying within the class constructor that before any user can access anything provided by this class, they must be authenticated. There is nothing wrong with doing it this way, but many developers might argue that it’s better to prevent the request from even getting to the controller class. We should add validation to the route so that it verifies that the user is authenticated even before sending the request through to the controller class. First, we can remove the constructor from our ServicesController class, since we’ll be adding the middleware from our routes/web.php file. Then we can update our routes file as follows:

app/Http/Controllers/ServicesController.php
--- a/app/Http/Controllers/ServicesController.php
+++ b/app/Http/Controllers/ServicesController.php
@@ -7,11 +7,6 @@ use Illuminate\Support\Facades\Auth;

 class ServicesController extends Controller
 {
-    public function __construct()
-    {
-        $this->middleware('auth');
-    }
-
     public function index()
     {
         $services = Service::byUser(Auth::user())->get();
routes/web.php
--- a/routes/web.php
+++ b/routes/web.php
-Route::get('/services', 'ServicesController@index')->name('services');
+/*
+|--------------------------------------------------------------------------
+| Application routes
+|--------------------------------------------------------------------------
+|
+| The following routes are application routes. That means an authentication
+| is absolutely necessary to access these on your browser.
+|
+*/
+
+Route::middleware(['auth'])->group(function () {
+    Route::get('/services', 'ServicesController@index')->name('services');
+});

Here we are creating a group of routes. Every route inside here will have the auth middleware applied.

Let’s create our first layout

We haven’t been using layouts to separate our HTML efficiently. We will create our first layout file now. Inside resources/views/layouts/ let’s create a file called skeleton.blade.php here we’ll add all the HTML that will be shared in our files.

resources/views/layouts/skeleton.blade.php
--- /dev/null
+++ b/resources/views/layouts/skeleton.blade.php
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <meta name="csrf-token" content="{{ csrf_token() }}">
+
+    <title>@yield('pageTitle', 'PingPing')</title>
+
+    <link href="https://fonts.googleapis.com/css?family=Lato:300,400,700" rel="stylesheet">
+    <link href="{{ mix('/css/app.css') }}" rel="stylesheet">
+</head>
+<body class="@yield('bodyClasses')">
+    @yield('body')
+</body>
+</html>

Let’s use our new layout file and update our login form

Let’s modify the resources/views/login.blade.php file to use the layout file we just created and we'll move it to a folder called auth. This is fairly simple, we just remove all the HTML that we pulled over to the layout. We’ll need to extend the layout and create a body section so it will be placed in the @yield portion of the layout.

On the episode "#003 - We build a login using TailwindCSS" we built our login form. Or at least a basic version of it. We need to modify our form also so that it submits to the login route we registered a while ago and sends the correct payload. Don't forget, to move the file from resources/views/login.blade.php to resources/views/auth/login.blade.php as you can see in the diff below.

resources/views/auth/login.blade.php
--- a/resources/views/login.blade.php
+++ b/resources/views/auth/login.blade.php
@@ -1,19 +1,10 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
-    <meta charset="utf-8">
-    <meta http-equiv="X-UA-Compatible" content="IE=edge">
-    <meta name="viewport" content="width=device-width, initial-scale=1">
-    <meta name="csrf-token" content="{{ csrf_token() }}">
+@extends('layouts.skeleton')

-    <title>Login</title>
+@section('pageTitle', 'PingPing - Login')
+@section('bodyClasses', 'bg-grey-lighter text-base text-grey-darkest font-normal relative')

-    <link href="https://fonts.googleapis.com/css?family=Lato:300,400,700" rel="stylesheet">
-    <link href="{{ mix('/css/app.css') }}" rel="stylesheet">
-</head>
-<body class="bg-grey-lighter text-base text-grey-darkest font-normal relative">
+@section('body')
     <div class="h-2 bg-primary"></div>
-
     <div class="container mx-auto p-8">
         <div class="mx-auto max-w-sm">
             <div class="py-10 text-center">
@@ -25,17 +16,23 @@
                     Welcome back!
                 </div>

-                <form class="bg-grey-lightest px-10 py-10">
+                <form action="/login" method="post" class="bg-grey-lightest px-10 py-10">
                     {{ csrf_field() }}

                     <div class="mb-3">
-                        <input class="border w-full p-3" name="email" type="text" placeholder="E-Mail">
+                        <input class="border {{ $errors->first('email') ? 'border-red' : '' }} w-full p-3" name="email" type="text" placeholder="E-Mail">
+                        @if ($errors->first('email'))
+                            <p class="text-red text-sm mt-1">{{ $errors->first('email') }}</p>
+                        @endif
                     </div>
                     <div class="mb-6">
-                        <input class="border w-full p-3" name="password" type="password" placeholder="**************">
+                        <input class="border {{ $errors->first('password') ? 'border-red' : '' }} w-full p-3" name="password" type="password" placeholder="**************">
+                        @if ($errors->first('password'))
+                            <p class="text-red text-sm mt-1">{{ $errors->first('password') }}</p>
+                        @endif
                     </div>
                     <div class="flex">
-                        <button class="bg-primary hover:bg-primary-dark w-full p-4 text-sm text-white uppercase font-bold tracking-wider">
+                        <button type="submit" class="bg-primary hover:bg-primary-dark w-full p-4 text-sm text-white uppercase font-bold tracking-wider">
                             Login
                         </button>
                     </div>
@@ -50,5 +47,4 @@
             </div>
         </div>
     </div>
-</body>
-</html>
+@stop

Here we are doing quite a few things. We updated the action attribute on the form and set the method attribute to post. We are doing some checks for validation errors to apply different styles on the inputs and we are displaying the errors sent back from the server. We also added a type attribute equal to submit on our button.

Create a new color in our TailwindCSS configuration file

Last but not least, we need to create a new color in our tailwind.js file. In this file, we can configure every little part of Tailwind. Here we’ll simply add a new color attribute to our colors object.

tailwind.js
--- a/tailwind.js
+++ b/tailwind.js
@@ -57,7 +57,9 @@ let colors = {
   'white': '#ffffff',

   'primary': '#2b79c1',
-  'primary-dark': '#266299'
+  'primary-dark': '#266299',
+
+  'red': '#bf6464',
 }

You need to compile your assets again so that Tailwind generates our newly added color.

We did only a few things, but they were very important. Thanks for following the progress on building PingPing, hopefully, you are enjoying these posts.

Bobby Bouwmann and I are writing a book called "Laravel Secrets".
You will learn everything about the undocumented secrets of the popular Laravel framework. You can sign up using the form below to get early updates.
      Visit laravelsecrets.com to get more information.