diff --git a/src/Illuminate/Auth/Events/Validated.php b/src/Illuminate/Auth/Events/Validated.php new file mode 100644 index 000000000000..ebc3b2ce1797 --- /dev/null +++ b/src/Illuminate/Auth/Events/Validated.php @@ -0,0 +1,37 @@ +user = $user; + $this->guard = $guard; + } +} diff --git a/src/Illuminate/Auth/SessionGuard.php b/src/Illuminate/Auth/SessionGuard.php index 72177dfdbf77..cceb853f61b6 100644 --- a/src/Illuminate/Auth/SessionGuard.php +++ b/src/Illuminate/Auth/SessionGuard.php @@ -9,6 +9,7 @@ use Illuminate\Auth\Events\Login; use Illuminate\Auth\Events\Logout; use Illuminate\Auth\Events\OtherDeviceLogout; +use Illuminate\Auth\Events\Validated; use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract; use Illuminate\Contracts\Auth\StatefulGuard; use Illuminate\Contracts\Auth\SupportsBasicAuth; @@ -367,7 +368,7 @@ public function attempt(array $credentials = [], $remember = false) // If the authentication attempt fails we will fire an event so that the user // may be notified of any suspicious attempts to access their account from // an unrecognized user. A developer may listen to this event as needed. - $this->fireFailedEvent($user, $credentials); + $this->fireFailedEvent($this->lastAttempted, $credentials); return false; } @@ -381,7 +382,13 @@ public function attempt(array $credentials = [], $remember = false) */ protected function hasValidCredentials($user, $credentials) { - return ! is_null($user) && $this->provider->validateCredentials($user, $credentials); + $validated = ! is_null($user) && $this->provider->validateCredentials($user, $credentials); + + if ($validated) { + $this->fireValidatedEvent($user); + } + + return $validated; } /** @@ -622,6 +629,20 @@ protected function fireAttemptEvent(array $credentials, $remember = false) } } + /** + * Fires the retrieved event if the dispatcher is set. + * + * @param $user + */ + protected function fireValidatedEvent($user) + { + if (isset($this->events)) { + $this->events->dispatch(new Validated( + $this->name, $user + )); + } + } + /** * Fire the login event if the dispatcher is set. * diff --git a/tests/Auth/AuthGuardTest.php b/tests/Auth/AuthGuardTest.php index 9a512a61ce18..4399268a90ad 100755 --- a/tests/Auth/AuthGuardTest.php +++ b/tests/Auth/AuthGuardTest.php @@ -9,6 +9,7 @@ use Illuminate\Auth\Events\Failed; use Illuminate\Auth\Events\Login; use Illuminate\Auth\Events\Logout; +use Illuminate\Auth\Events\Validated; use Illuminate\Auth\SessionGuard; use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Contracts\Auth\UserProvider; @@ -96,6 +97,7 @@ public function testAttemptCallsRetrieveByCredentials() $guard->setDispatcher($events = m::mock(Dispatcher::class)); $events->shouldReceive('dispatch')->once()->with(m::type(Attempting::class)); $events->shouldReceive('dispatch')->once()->with(m::type(Failed::class)); + $events->shouldNotReceive('dispatch')->with(m::type(Validated::class)); $guard->getProvider()->shouldReceive('retrieveByCredentials')->once()->with(['foo']); $guard->attempt(['foo']); } @@ -106,6 +108,7 @@ public function testAttemptReturnsUserInterface() $guard = $this->getMockBuilder(SessionGuard::class)->setMethods(['login'])->setConstructorArgs(['default', $provider, $session, $request])->getMock(); $guard->setDispatcher($events = m::mock(Dispatcher::class)); $events->shouldReceive('dispatch')->once()->with(m::type(Attempting::class)); + $events->shouldReceive('dispatch')->once()->with(m::type(Validated::class)); $user = $this->createMock(Authenticatable::class); $guard->getProvider()->shouldReceive('retrieveByCredentials')->once()->andReturn($user); $guard->getProvider()->shouldReceive('validateCredentials')->with($user, ['foo'])->andReturn(true); @@ -119,6 +122,7 @@ public function testAttemptReturnsFalseIfUserNotGiven() $mock->setDispatcher($events = m::mock(Dispatcher::class)); $events->shouldReceive('dispatch')->once()->with(m::type(Attempting::class)); $events->shouldReceive('dispatch')->once()->with(m::type(Failed::class)); + $events->shouldNotReceive('dispatch')->with(m::type(Validated::class)); $mock->getProvider()->shouldReceive('retrieveByCredentials')->once()->andReturn(null); $this->assertFalse($mock->attempt(['foo'])); } @@ -169,6 +173,7 @@ public function testFailedAttemptFiresFailedEvent() $guard->setDispatcher($events = m::mock(Dispatcher::class)); $events->shouldReceive('dispatch')->once()->with(m::type(Attempting::class)); $events->shouldReceive('dispatch')->once()->with(m::type(Failed::class)); + $events->shouldNotReceive('dispatch')->with(m::type(Validated::class)); $guard->getProvider()->shouldReceive('retrieveByCredentials')->once()->with(['foo'])->andReturn(null); $guard->attempt(['foo']); } diff --git a/tests/Integration/Auth/AuthenticationTest.php b/tests/Integration/Auth/AuthenticationTest.php index 8067bf03014c..afab4366b6b6 100644 --- a/tests/Integration/Auth/AuthenticationTest.php +++ b/tests/Integration/Auth/AuthenticationTest.php @@ -9,6 +9,7 @@ use Illuminate\Auth\Events\Login; use Illuminate\Auth\Events\Logout; use Illuminate\Auth\Events\OtherDeviceLogout; +use Illuminate\Auth\Events\Validated; use Illuminate\Auth\SessionGuard; use Illuminate\Database\Schema\Blueprint; use Illuminate\Events\Dispatcher; @@ -126,6 +127,7 @@ public function testLoggingInFailsViaAttempt() return true; }); + Event::assertNotDispatched(Validated::class); Event::assertDispatched(Failed::class, function ($event) { $this->assertSame('web', $event->guard); $this->assertEquals(['email' => 'wrong', 'password' => 'password'], $event->credentials); @@ -151,6 +153,12 @@ public function testLoggingInSucceedsViaAttempt() return true; }); + Event::assertDispatched(Validated::class, function ($event) { + $this->assertSame('web', $event->guard); + $this->assertEquals(1, $event->user->id); + + return true; + }); Event::assertDispatched(Login::class, function ($event) { $this->assertSame('web', $event->guard); $this->assertEquals(1, $event->user->id);