Description
Current situation
The authenticators load a user in the authenticate(Request $request): PassportInterface
method and return a passport with the user instance and any credentials/badges.
public function authenticate(Request $request): PassportInterface
{
$user = $this->userRepository->findOneByUsername($request->get('_username'));
if (!$user) {
throw new UsernameNotFoundException();
}
return new Passport($user, ...);
}
This method was chosen as it allowed to merge the getCredentials()
, getUser()
and checkCredentials()
methods of Guard into 1 method, making things easier to understand and use.
The limitations
However, while working on some new features, I found a major limitation of th
694E
is idea: The first place to hook into the authentication process is after the user is loaded.
This prevents things like checking CSRF or login throttling before interacting with the database (preventing server load in spam requests) and allowing login throttling to work for invalid usernames (currently, a login throttling listener on CheckPassportEvent needs a valid username in order to be called).
The solution
A possible solution I can think of is also making user loading part of the badge system, creating 2 default ways to load users:
- Using the preconfigured
UserProviderInterface
:public function authenticate(Request $request): PassportInterface { return new Passport( new UserFromProvider($request->get('_username')), new PasswordCredentials($request->get('_password')), [new LoginThrottlingBadge($request->get('_username')] ); }
- Using a closure:
public function authenticate(Request $request): PassportInterface { return new Passport( new UserFromClosure($request->get('_username'), [$this, 'loadUser']), new PasswordCredentials($request->get('_password')), [new LoginThrottlingBadge($request->get('_username')] ); } public function loadUser(string $username): UserInterface { return $this->userRepository->findOneByUsername($username); }