From a749d76c198db4af7245ed2ecc15bdc06f5df1ec Mon Sep 17 00:00:00 2001 From: Fernando Kupper Cardoso Date: Fri, 2 Jul 2021 11:11:14 +0200 Subject: [PATCH 1/3] feat: dispatch Attempt, Validated, and Failed events --- src/JWTGuard.php | 85 ++++++++++++++++++++++- src/Providers/AbstractServiceProvider.php | 3 +- 2 files changed, 84 insertions(+), 4 deletions(-) diff --git a/src/JWTGuard.php b/src/JWTGuard.php index 28f477fa6..ab8fa5902 100644 --- a/src/JWTGuard.php +++ b/src/JWTGuard.php @@ -12,9 +12,13 @@ namespace Tymon\JWTAuth; use BadMethodCallException; +use Illuminate\Auth\Events\Attempting; +use Illuminate\Auth\Events\Failed; +use Illuminate\Auth\Events\Validated; use Illuminate\Auth\GuardHelpers; use Illuminate\Contracts\Auth\Guard; use Illuminate\Contracts\Auth\UserProvider; +use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Http\Request; use Illuminate\Support\Traits\Macroable; use Tymon\JWTAuth\Contracts\JWTSubject; @@ -48,20 +52,40 @@ class JWTGuard implements Guard */ protected $request; + /** + * The event dispatcher instance. + * + * @var \Illuminate\Contracts\Events\Dispatcher + */ + protected $events; + + /** + * The name of the Guard. + * + * @var string + */ + protected $name = 'tymon.jwt'; + /** * Instantiate the class. * * @param \Tymon\JWTAuth\JWT $jwt * @param \Illuminate\Contracts\Auth\UserProvider $provider * @param \Illuminate\Http\Request $request + * @param \Illuminate\Contracts\Events\Dispatcher $eventDispatcher * * @return void */ - public function __construct(JWT $jwt, UserProvider $provider, Request $request) - { + public function __construct( + JWT $jwt, + UserProvider $provider, + Request $request, + Dispatcher $eventDispatcher + ) { $this->jwt = $jwt; $this->provider = $provider; $this->request = $request; + $this->events = $eventDispatcher; } /** @@ -123,10 +147,14 @@ public function attempt(array $credentials = [], $login = true) { $this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials); + $this->fireAttemptEvent($credentials); + if ($this->hasValidCredentials($user, $credentials)) { return $login ? $this->login($user) : true; } + $this->fireFailedEvent($user, $credentials); + return false; } @@ -387,7 +415,13 @@ public function getLastAttempted() */ protected function hasValidCredentials($user, $credentials) { - return $user !== null && $this->provider->validateCredentials($user, $credentials); + $validated = $user !== null && $this->provider->validateCredentials($user, $credentials); + + if ($validated) { + $this->fireValidatedEvent($user); + } + + return $validated; } /** @@ -422,6 +456,51 @@ protected function requireToken() return $this->jwt; } + /** + * Fire the attempt event. + * + * @param array $credentials + * @return void + */ + protected function fireAttemptEvent(array $credentials) + { + $this->events->dispatch(new Attempting( + $this->name, + $credentials, + false + )); + } + + /** + * Fires the validated event. + * + * @param \Illuminate\Contracts\Auth\Authenticatable $user + * @return void + */ + protected function fireValidatedEvent($user) + { + $this->events->dispatch(new Validated( + $this->name, + $user + )); + } + + /** + * Fire the failed authentication attempt event. + * + * @param \Illuminate\Contracts\Auth\Authenticatable|null $user + * @param array $credentials + * @return void + */ + protected function fireFailedEvent($user, array $credentials) + { + $this->events->dispatch(new Failed( + $this->name, + $user, + $credentials + )); + } + /** * Magically call the JWT instance. * diff --git a/src/Providers/AbstractServiceProvider.php b/src/Providers/AbstractServiceProvider.php index ca312a40e..723555aca 100644 --- a/src/Providers/AbstractServiceProvider.php +++ b/src/Providers/AbstractServiceProvider.php @@ -97,7 +97,8 @@ protected function extendAuthGuard() $guard = new JWTGuard( $app['tymon.jwt'], $app['auth']->createUserProvider($config['provider']), - $app['request'] + $app['request'], + $app['events'] ); $app->refresh('request', $guard, 'setRequest'); From ad6af0cf36a562ea7b22094008451049cfa1f0c6 Mon Sep 17 00:00:00 2001 From: Fernando Kupper Cardoso Date: Fri, 2 Jul 2021 11:11:24 +0200 Subject: [PATCH 2/3] chore: add tests --- tests/JWTGuardTest.php | 58 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/tests/JWTGuardTest.php b/tests/JWTGuardTest.php index d15ca5a50..f96540785 100644 --- a/tests/JWTGuardTest.php +++ b/tests/JWTGuardTest.php @@ -12,8 +12,13 @@ namespace Tymon\JWTAuth\Test; use Illuminate\Auth\EloquentUserProvider; +use Illuminate\Auth\Events\Attempting; +use Illuminate\Auth\Events\Failed; +use Illuminate\Auth\Events\Validated; +use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Http\Request; use Mockery; +use Mockery\Mock; use Tymon\JWTAuth\Exceptions\JWTException; use Tymon\JWTAuth\Exceptions\UserNotDefinedException; use Tymon\JWTAuth\Factory; @@ -39,13 +44,24 @@ class JWTGuardTest extends AbstractTestCase */ protected $guard; + /** + * @var \lluminate\Contracts\Events\Dispatcher|\Mockery\MockInterface + */ + protected $eventDispatcher; + public function setUp(): void { parent::setUp(); $this->jwt = Mockery::mock(JWT::class); $this->provider = Mockery::mock(EloquentUserProvider::class); - $this->guard = new JWTGuard($this->jwt, $this->provider, Request::create('/foo', 'GET')); + $this->eventDispatcher = Mockery::mock(Dispatcher::class); + $this->guard = new JWTGuard( + $this->jwt, + $this->provider, + Request::create('/foo', 'GET'), + $this->eventDispatcher + ); } /** @test */ @@ -204,6 +220,14 @@ public function it_should_return_a_token_if_credentials_are_ok_and_user_is_found ->with(['foo' => 'bar']) ->andReturnSelf(); + $this->eventDispatcher->shouldReceive('dispatch') + ->once() + ->with(Mockery::type(Attempting::class)); + + $this->eventDispatcher->shouldReceive('dispatch') + ->once() + ->with(Mockery::type(Validated::class)); + $token = $this->guard->claims(['foo' => 'bar'])->attempt($credentials); $this->assertSame($this->guard->getLastAttempted(), $user); @@ -226,6 +250,14 @@ public function it_should_return_true_if_credentials_are_ok_and_user_is_found_wh ->with($user, $credentials) ->andReturn(true); + $this->eventDispatcher->shouldReceive('dispatch') + ->twice() + ->with(Mockery::type(Attempting::class)); + + $this->eventDispatcher->shouldReceive('dispatch') + ->twice() + ->with(Mockery::type(Validated::class)); + $this->assertTrue($this->guard->attempt($credentials, false)); // once $this->assertTrue($this->guard->validate($credentials)); // twice } @@ -246,6 +278,14 @@ public function it_should_return_false_if_credentials_are_invalid() ->with($user, $credentials) ->andReturn(false); + $this->eventDispatcher->shouldReceive('dispatch') + ->once() + ->with(Mockery::type(Attempting::class)); + + $this->eventDispatcher->shouldReceive('dispatch') + ->once() + ->with(Mockery::type(Failed::class)); + $this->assertFalse($this->guard->attempt($credentials)); } @@ -346,6 +386,14 @@ public function it_should_authenticate_the_user_by_credentials_and_return_true_i ->with($user, $credentials) ->andReturn(true); + $this->eventDispatcher->shouldReceive('dispatch') + ->once() + ->with(Mockery::type(Attempting::class)); + + $this->eventDispatcher->shouldReceive('dispatch') + ->once() + ->with(Mockery::type(Validated::class)); + $this->assertTrue($this->guard->once($credentials)); } @@ -365,6 +413,14 @@ public function it_should_attempt_to_authenticate_the_user_by_credentials_and_re ->with($user, $credentials) ->andReturn(false); + $this->eventDispatcher->shouldReceive('dispatch') + ->once() + ->with(Mockery::type(Attempting::class)); + + $this->eventDispatcher->shouldReceive('dispatch') + ->once() + ->with(Mockery::type(Failed::class)); + $this->assertFalse($this->guard->once($credentials)); } From 3a5aeffc37467bce74bb6a6b5066badfbebc73dd Mon Sep 17 00:00:00 2001 From: Fernando Kupper Cardoso Date: Fri, 2 Jul 2021 12:06:23 +0200 Subject: [PATCH 3/3] chore: fix standards --- src/JWTGuard.php | 3 +++ tests/JWTGuardTest.php | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/JWTGuard.php b/src/JWTGuard.php index ab8fa5902..0a1c6672b 100644 --- a/src/JWTGuard.php +++ b/src/JWTGuard.php @@ -460,6 +460,7 @@ protected function requireToken() * Fire the attempt event. * * @param array $credentials + * * @return void */ protected function fireAttemptEvent(array $credentials) @@ -475,6 +476,7 @@ protected function fireAttemptEvent(array $credentials) * Fires the validated event. * * @param \Illuminate\Contracts\Auth\Authenticatable $user + * * @return void */ protected function fireValidatedEvent($user) @@ -490,6 +492,7 @@ protected function fireValidatedEvent($user) * * @param \Illuminate\Contracts\Auth\Authenticatable|null $user * @param array $credentials + * * @return void */ protected function fireFailedEvent($user, array $credentials) diff --git a/tests/JWTGuardTest.php b/tests/JWTGuardTest.php index f96540785..01cd13254 100644 --- a/tests/JWTGuardTest.php +++ b/tests/JWTGuardTest.php @@ -18,7 +18,6 @@ use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Http\Request; use Mockery; -use Mockery\Mock; use Tymon\JWTAuth\Exceptions\JWTException; use Tymon\JWTAuth\Exceptions\UserNotDefinedException; use Tymon\JWTAuth\Factory;