Customizing Laravel Authentication: Implementing Your Own Login System

October 18, 2024By Rakshit Patel

Laravel provides a robust authentication system right out of the box. However, in many real-world scenarios, you may need to customize or extend this functionality to suit your application’s unique requirements. In this article, we’ll walk through the steps to customize Laravel’s authentication system, including creating a custom login system, modifying user credentials, and enhancing security.

1. Understanding Laravel’s Default Authentication

Laravel’s default authentication system includes a set of routes, controllers, and views that make it easy to manage user authentication. By running php artisan make:auth (in Laravel versions before 8), or manually configuring routes in Laravel 8 and above, you can generate the necessary login, registration, and password reset functionality.

However, to build a custom login system, we will go beyond these defaults, allowing us to:

  • Use custom fields for login (e.g., username instead of email).
  • Modify authentication logic.
  • Add additional security layers (e.g., two-factor authentication).

2. Setting Up the Authentication Routes

The first step in creating a custom login system is setting up your routes. You can define custom authentication routes in the routes/web.php file:

use App\Http\Controllers\Auth\LoginController;

Route::get('login', [LoginController::class, 'showLoginForm'])->name('login');
Route::post('login', [LoginController::class, 'login']);
Route::post('logout', [LoginController::class, 'logout'])->name('logout');

Here, we define routes for showing the login form, processing login attempts, and logging users out.

3. Creating a Custom Login Controller

Next, you will need to create a custom LoginController to handle the authentication logic. You can start by generating the controller:

php artisan make:controller Auth/LoginController

In your LoginController.php, you can customize the login behavior as follows:

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class LoginController extends Controller
{
public function showLoginForm()
{
return view('auth.login');
}

public function login(Request $request)
{
// Custom validation logic
$credentials = $request->validate([
'username' => 'required|string',
'password' => 'required|string',
]);

// Attempt to log the user in with custom credentials
if (Auth::attempt($credentials)) {
// Authentication successful, redirect to intended page
return redirect()->intended('dashboard');
}

// If login fails, redirect back with error
return back()->withErrors([
'username' => 'The provided credentials do not match our records.',
]);
}

public function logout()
{
Auth::logout();
return redirect('/');
}
}

Key Features of the Custom Login:

  • Custom Fields: We use username instead of email.
  • Authentication Attempt: The Auth::attempt() method checks if the credentials match a user in the database.
  • Redirect: Upon successful login, the user is redirected to the intended page or a default route (e.g., dashboard).
  • Validation: We validate the login request to ensure required fields are provided.

4. Customizing the Login View

Next, create a custom login form by editing or creating the resources/views/auth/login.blade.php view file:

<form method="POST" action="{{ route('login') }}">
@csrf
<div>
<label for="username">Username</label>
<input id="username" type="text" name="username" required autofocus>
</div>

<div>
<label for="password">Password</label>
<input id="password" type="password" name="password" required>
</div>

<div>
<button type="submit">Login</button>
</div>
</form>

In this form, we’ve replaced the email field with a username field. The view is simple but can be expanded with features like “Remember Me” or password reset links.

5. Customizing the User Model

To handle custom fields like username for authentication, you will need to modify the User model. Open the app/Models/User.php file and ensure that the username field is mass-assignable:

class User extends Authenticatable
{
protected $fillable = [
'username', 'email', 'password',
];

protected $hidden = [
'password', 'remember_token',
];
}

If you’re using Laravel’s default Auth::attempt(), it will automatically check against the password field in your database. Ensure that your database migration includes a username field, which can be done using:

Schema::table('users', function (Blueprint $table) {
$table->string('username')->unique();
});

6. Handling Login via Multiple Fields

Sometimes, you may want users to log in via either a username or an email. To handle this, modify the login logic in LoginController:

public function login(Request $request)
{
$loginType = filter_var($request->input('login'), FILTER_VALIDATE_EMAIL) ? 'email' : 'username';

$credentials = [
$loginType => $request->input('login'),
'password' => $request->input('password'),
];

if (Auth::attempt($credentials)) {
return redirect()->intended('dashboard');
}

return back()->withErrors([
'login' => 'The provided credentials do not match our records.',
]);
}

In this example, users can input either an email or a username into the login field, and the system will determine how to authenticate them.

7. Enhancing Security: Rate Limiting and Throttling

To prevent brute-force attacks, it’s important to add login throttling. Laravel includes a ThrottleRequests middleware that can be applied to routes. To enable this, you can modify the LoginController:

use Illuminate\Foundation\Auth\ThrottlesLogins;

class LoginController extends Controller
{
use ThrottlesLogins;

protected function login(Request $request)
{
if ($this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}

if (Auth::attempt($request->only('username', 'password'))) {
$this->clearLoginAttempts($request);
return redirect()->intended('dashboard');
}

$this->incrementLoginAttempts($request);
return back()->withErrors(['username' => 'Invalid credentials.']);
}

public function username()
{
return 'username'; // Specify the field used for login
}
}

This will automatically throttle login attempts and lock out users after too many failed attempts within a specific timeframe.

8. Adding Remember Me Functionality

To add “Remember Me” functionality, modify the login form and update the login logic:

In the Blade view (login.blade.php):

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

In the LoginController:

if (Auth::attempt($credentials, $request->filled('remember'))) {
return redirect()->intended('dashboard');
}

This enables persistent login sessions, even after users close their browsers.

9. Custom Redirects After Login

To control where users are redirected after login, you can modify the LoginController by setting a custom redirect path:

protected function redirectTo()
{
return '/custom-dashboard';
}

Alternatively, you can define the redirectTo path dynamically based on the user’s role or other conditions.

10. Logging and Event Listeners

For security auditing, you may want to log every login attempt or listen for successful logins and trigger additional actions. Laravel’s authentication system includes several events you can hook into, such as Login, Logout, and Failed.

Example: Logging login events

Create an event listener:

php artisan make:listener LogSuccessfulLogin

Then, in LogSuccessfulLogin.php:

public function handle(Login $event)
{
Log::info('User logged in: ', ['user' => $event->user->username]);
}

Register the listener in EventServiceProvider.php under the $listen array:

protected $listen = [
'Illuminate\Auth\Events\Login' => [
'App\Listeners\LogSuccessfulLogin',
],
];

Conclusion

Laravel’s authentication system is powerful yet flexible, allowing you to create a customized login system that meets the specific needs of your application. From using custom fields like username, adding security with throttling, handling multiple login methods, to creating event listeners, Laravel provides a robust framework that you can easily extend. By following these techniques, you can build a secure and user-friendly authentication system tailored to your project.

Rakshit Patel

Author ImageI am the Founder of Crest Infotech With over 15 years’ experience in web design, web development, mobile apps development and content marketing. I ensure that we deliver quality website to you which is optimized to improve your business, sales and profits. We create websites that rank at the top of Google and can be easily updated by you.

CATEGORIES