Skip to content

Commit

Permalink
Adds attemptWith() with tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
DarkGhostHunter committed Apr 22, 2021
1 parent a011109 commit 67fd7ad
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 0 deletions.
47 changes: 47 additions & 0 deletions src/Illuminate/Auth/SessionGuard.php
Expand Up @@ -17,6 +17,7 @@
use Illuminate\Contracts\Cookie\QueueingFactory as CookieJar;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Contracts\Session\Session;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
use Illuminate\Support\Traits\Macroable;
Expand Down Expand Up @@ -374,6 +375,34 @@ public function attempt(array $credentials = [], $remember = false)
return false;
}

/**
* Attempt to authenticate a user with credentials and additional callbacks.
*
* @param array $credentials
* @param false $remember
* @param array|callable $callbacks
* @return bool
*/
public function attemptWith(array $credentials = [], $remember = false, $callbacks = null)
{
$this->fireAttemptEvent($credentials, $remember);

$this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials);

// This method does the exact same thing as Attempt, but also executes callbacks after
// the user is retrieved and validated. If one of the callbacks returns falsy, we
// won't login this user. Instead, we will fail this authentication attempt.
if ($this->hasValidCredentials($user, $credentials) && $this->shouldLogin($callbacks, $user)) {
$this->login($user, $remember);

return true;
}

$this->fireFailedEvent($user, $credentials);

return false;
}

/**
* Determine if the user matches the credentials.
*
Expand All @@ -392,6 +421,24 @@ protected function hasValidCredentials($user, $credentials)
return $validated;
}

/**
* Checks if the user should login by executing the given callbacks.
*
* @param array|callable|null $callbacks
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @return bool
*/
protected function shouldLogin($callbacks, AuthenticatableContract $user)
{
foreach (Arr::wrap($callbacks) as $callback) {
if (! $callback($user, $this)) {
return false;
}
}

return true;
}

/**
* Log the given user ID into the application.
*
Expand Down
42 changes: 42 additions & 0 deletions tests/Auth/AuthGuardTest.php
Expand Up @@ -126,6 +126,48 @@ public function testAttemptReturnsFalseIfUserNotGiven()
$this->assertFalse($mock->attempt(['foo']));
}

public function testAttemptAndWithCallbacks()
{
[$session, $provider, $request, $cookie] = $this->getMocks();
$mock = $this->getMockBuilder(SessionGuard::class)->onlyMethods(['getName'])->setConstructorArgs(['default', $provider, $session, $request])->getMock();
$mock->setDispatcher($events = m::mock(Dispatcher::class));
$user = m::mock(Authenticatable::class);
$events->shouldReceive('dispatch')->times(3)->with(m::type(Attempting::class));
$events->shouldReceive('dispatch')->once()->with(m::type(Login::class));
$events->shouldReceive('dispatch')->once()->with(m::type(Authenticated::class));
$events->shouldReceive('dispatch')->twice()->with(m::type(Validated::class));
$events->shouldReceive('dispatch')->twice()->with(m::type(Failed::class));
$mock->expects($this->once())->method('getName')->willReturn('foo');
$user->shouldReceive('getAuthIdentifier')->once()->andReturn('bar');
$mock->getSession()->shouldReceive('put')->with('foo', 'bar')->once();
$session->shouldReceive('migrate')->once();
$mock->getProvider()->shouldReceive('retrieveByCredentials')->times(3)->with(['foo'])->andReturn($user);
$mock->getProvider()->shouldReceive('validateCredentials')->twice()->andReturnTrue();
$mock->getProvider()->shouldReceive('validateCredentials')->once()->andReturnFalse();

$this->assertTrue($mock->attemptWith(['foo'], false, function ($user, $guard) {
static::assertInstanceOf(Authenticatable::class, $user);
static::assertInstanceOf(SessionGuard::class, $guard);

return true;
}));

$this->assertFalse($mock->attemptWith(['foo'], false, function ($user, $guard) {
static::assertInstanceOf(Authenticatable::class, $user);
static::assertInstanceOf(SessionGuard::class, $guard);

return false;
}));

$executed = false;

$this->assertFalse($mock->attemptWith(['foo'], false, function () use (&$executed) {
return $executed = true;
}));

$this->assertFalse($executed);
}

public function testLoginStoresIdentifierInSession()
{
[$session, $provider, $request, $cookie] = $this->getMocks();
Expand Down

0 comments on commit 67fd7ad

Please sign in to comment.