Replace direct password_hash and password_verify calls with the injected PasswordHasher so the bcrypt cost can be substituted out in tests. Production wiring is handled by the container's autowiring of BcryptPasswordHasher. This commit alone breaks the test suite because the existing tests construct these use cases without the new dependency; the next commit restores green by introducing FakePasswordHasher.
50 lines
1.3 KiB
PHP
50 lines
1.3 KiB
PHP
<?php
|
|
|
|
namespace App\User\UseCases;
|
|
|
|
use App\Auth\PasswordHasher;
|
|
use App\Exceptions\BadRequestException;
|
|
use App\Exceptions\UnauthorizedException;
|
|
use App\User\User;
|
|
use App\User\UserRepository;
|
|
use App\ValueObjects\EmailAddress;
|
|
|
|
class AuthenticateUser
|
|
{
|
|
public function __construct(
|
|
private UserRepository $userRepo,
|
|
private PasswordHasher $passwordHasher,
|
|
) {}
|
|
|
|
/**
|
|
* @throws BadRequestException
|
|
* @throws UnauthorizedException
|
|
*/
|
|
public function execute(AuthenticateUserRequest $request): User
|
|
{
|
|
if ($request->email === null) {
|
|
throw new BadRequestException('email is required');
|
|
}
|
|
|
|
if ($request->password === null) {
|
|
throw new BadRequestException('password is required');
|
|
}
|
|
|
|
$user = $this->userRepo->findByEmail(
|
|
new EmailAddress($request->email)
|
|
);
|
|
if ($user === null) {
|
|
throw new UnauthorizedException('invalid credentials');
|
|
}
|
|
|
|
$passwordMatches = $this->passwordHasher->verify(
|
|
$request->password,
|
|
$user->getPasswordHash()
|
|
);
|
|
if (!$passwordMatches) {
|
|
throw new UnauthorizedException('invalid credentials');
|
|
}
|
|
|
|
return $user;
|
|
}
|
|
}
|