Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[8.x] Adds attemptWith() with tests #37090

Merged
merged 1 commit into from
Apr 23, 2021
Merged

[8.x] Adds attemptWith() with tests #37090

merged 1 commit into from
Apr 23, 2021

Conversation

DarkGhostHunter
Copy link
Contributor

This PR expands on the discussion here about adding callbacks the the authentication attempt mechanism.

Problem

There is no way to add additional checks at runtime when using attempt(). Any addition forces the developer to create a new Guard, or use nonchalantly validate() and getLastAttempted(), and fire Attempting and Failed manually.

if (Auth::validate($credentials) && $user = Auth::getLastAttempted()) {
    if ($user->isAwesomeAndCool()) {
        Auth::login($user, $request->filled('remember'));
        Event::fire(Attempting('session', $credentials, $request->filled('remember')));
        return $this->redirect();
    }
    Event::fire(Failed(...));
}


return $this->sendAttemptFailed();

As you can see, this whole mess becomes spaghetti (yum!) code quickly.

Solution

This PR adds the SessionGuard::attemptWith() method. It's a carbon copy of the original attempt() method, but receives a third argument of one or multiple callbacks. After the user is validated, each of these run an additional check by receiving the validated User. If one callback returns false, the whole attempt fails.

$result = Auth::attempt($credentials, false, function (Authenticatable $user, SessionGuard $guard) {
    return $user->isAwesomeAndCool();
});

return $result 
    ? $this->redirect() 
    : $this->sendAttemptFailed();

Since there are callables, the developer can add its own checks, or use checks made by external packages, all while controlling manually the flow and order of these.

If the user validation fails, the callbacks are not executed, thus keeping the original validation procedure intact.

How it works

The change adds the attemptWith() and the internal method shouldLogin(). The latter executes each callback and returns false if one of them "fails". This is called after the user is properly validated:

if ($this->hasValidCredentials($user, $credentials) && $this->shouldLogin($callbacks, $user)) {
    $this->login($user, $remember);

     return true;
}

Since it's a new method, no breaking changes are in sight.

@DarkGhostHunter DarkGhostHunter changed the title Adds attemptWith() with tests. [8.x] Adds attemptWith() with tests. Apr 22, 2021
@GrahamCampbell GrahamCampbell changed the title [8.x] Adds attemptWith() with tests. [8.x] Adds attemptWith() with tests Apr 22, 2021
@taylorotwell taylorotwell merged commit 67fd7ad into laravel:8.x Apr 23, 2021
@DarkGhostHunter DarkGhostHunter deleted the feat/attempt-callbacks branch April 23, 2021 16:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants