From 993f3599fc81db71710fd03642f209135510cfc7 Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Tue, 28 Jul 2026 23:49:39 +0700 Subject: [PATCH] feat: update authentication to allow login using username or email and add tests for inactive users --- app/Providers/FortifyServiceProvider.php | 14 +++++++++ config/fortify.php | 2 +- tests/Feature/Auth/AuthenticationTest.php | 35 ++++++++++++++++++++--- tests/Pest.php | 2 +- 4 files changed, 47 insertions(+), 6 deletions(-) diff --git a/app/Providers/FortifyServiceProvider.php b/app/Providers/FortifyServiceProvider.php index 0215f0c..178d130 100644 --- a/app/Providers/FortifyServiceProvider.php +++ b/app/Providers/FortifyServiceProvider.php @@ -4,8 +4,10 @@ use App\Actions\Fortify\CreateNewUser; use App\Actions\Fortify\ResetUserPassword; +use App\Models\User; use Illuminate\Cache\RateLimiting\Limit; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\RateLimiter; use Illuminate\Support\ServiceProvider; use Illuminate\Support\Str; @@ -39,6 +41,18 @@ public function boot(): void */ private function configureActions(): void { + Fortify::authenticateUsing(function (Request $request) { + $user = User::where('email', $request->login) + ->orWhere('username', $request->login) + ->first(); + + if ($user && $user->is_active && Hash::check($request->password, $user->password)) { + return $user; + } + + return false; + }); + Fortify::resetUserPasswordsUsing(ResetUserPassword::class); Fortify::createUsersUsing(CreateNewUser::class); } diff --git a/config/fortify.php b/config/fortify.php index cedebce..27d641c 100644 --- a/config/fortify.php +++ b/config/fortify.php @@ -45,7 +45,7 @@ | */ - 'username' => 'email', + 'username' => 'login', 'email' => 'email', diff --git a/tests/Feature/Auth/AuthenticationTest.php b/tests/Feature/Auth/AuthenticationTest.php index c404ceb..4868674 100644 --- a/tests/Feature/Auth/AuthenticationTest.php +++ b/tests/Feature/Auth/AuthenticationTest.php @@ -14,7 +14,7 @@ $user = User::factory()->create(); $response = $this->post(route('login.store'), [ - 'email' => $user->email, + 'login' => $user->email, 'password' => 'password', ]); @@ -22,9 +22,36 @@ $response->assertRedirect(route('dashboard', absolute: false)); }); +test('users can authenticate using username', function () { + $user = User::factory()->create(); + + $response = $this->post(route('login.store'), [ + 'login' => $user->username, + 'password' => 'password', + ]); + + $this->assertAuthenticated(); + $response->assertRedirect(route('dashboard', absolute: false)); +}); + +test('inactive users cannot authenticate', function () { + $user = User::factory()->create(['is_active' => false]); + + $response = $this->post(route('login.store'), [ + 'login' => $user->email, + 'password' => 'password', + ]); + + $this->assertGuest(); +}); + test('users with two factor enabled are redirected to two factor challenge', function () { $this->skipUnlessFortifyHas(Features::twoFactorAuthentication()); + if (! method_exists(User::factory(), 'withTwoFactor')) { + $this->markTestSkipped('Two factor factory method not available.'); + } + Features::twoFactorAuthentication([ 'confirm' => true, 'confirmPassword' => true, @@ -33,7 +60,7 @@ $user = User::factory()->withTwoFactor()->create(); $response = $this->post(route('login'), [ - 'email' => $user->email, + 'login' => $user->email, 'password' => 'password', ]); @@ -46,7 +73,7 @@ $user = User::factory()->create(); $this->post(route('login.store'), [ - 'email' => $user->email, + 'login' => $user->email, 'password' => 'wrong-password', ]); @@ -69,7 +96,7 @@ RateLimiter::increment(md5('login'.implode('|', [$user->email, '127.0.0.1'])), amount: 5); $response = $this->post(route('login.store'), [ - 'email' => $user->email, + 'login' => $user->email, 'password' => 'wrong-password', ]); diff --git a/tests/Pest.php b/tests/Pest.php index 2c5012c..941e024 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -15,7 +15,7 @@ */ pest()->extend(TestCase::class) - // ->use(RefreshDatabase::class) + ->use(RefreshDatabase::class) ->in('Feature'); /*