Refatoring : Working state
This commit is contained in:
109
src/Auth/Application/AuthApplicationService.php
Normal file
109
src/Auth/Application/AuthApplicationService.php
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Auth\Application;
|
||||
|
||||
use App\Auth\AuthServiceInterface;
|
||||
use App\Auth\Domain\LoginRateLimitPolicy;
|
||||
use App\Auth\LoginAttemptRepositoryInterface;
|
||||
use App\Shared\Exception\NotFoundException;
|
||||
use App\Shared\Http\SessionManagerInterface;
|
||||
use App\User\Exception\WeakPasswordException;
|
||||
use App\User\User;
|
||||
use App\User\UserRepositoryInterface;
|
||||
|
||||
class AuthApplicationService implements AuthServiceInterface
|
||||
{
|
||||
private readonly LoginRateLimitPolicy $rateLimitPolicy;
|
||||
|
||||
public function __construct(
|
||||
private readonly UserRepositoryInterface $userRepository,
|
||||
private readonly SessionManagerInterface $sessionManager,
|
||||
private readonly LoginAttemptRepositoryInterface $loginAttemptRepository,
|
||||
?LoginRateLimitPolicy $rateLimitPolicy = null,
|
||||
) {
|
||||
$this->rateLimitPolicy = $rateLimitPolicy ?? new LoginRateLimitPolicy();
|
||||
}
|
||||
|
||||
public function checkRateLimit(string $ip): int
|
||||
{
|
||||
$this->loginAttemptRepository->deleteExpired();
|
||||
|
||||
$row = $this->loginAttemptRepository->findByIp($ip);
|
||||
|
||||
if ($row === null || $row['locked_until'] === null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$lockedUntil = new \DateTime($row['locked_until']);
|
||||
$now = new \DateTime();
|
||||
|
||||
if ($lockedUntil <= $now) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$secondsLeft = $lockedUntil->getTimestamp() - $now->getTimestamp();
|
||||
|
||||
return max(1, (int) ceil($secondsLeft / 60));
|
||||
}
|
||||
|
||||
public function recordFailure(string $ip): void
|
||||
{
|
||||
$this->loginAttemptRepository->recordFailure($ip, $this->rateLimitPolicy->maxAttempts(), $this->rateLimitPolicy->lockMinutes());
|
||||
}
|
||||
|
||||
public function resetRateLimit(string $ip): void
|
||||
{
|
||||
$this->loginAttemptRepository->resetForIp($ip);
|
||||
}
|
||||
|
||||
public function authenticate(string $username, string $plainPassword): ?User
|
||||
{
|
||||
$user = $this->userRepository->findByUsername(mb_strtolower(trim($username)));
|
||||
|
||||
if ($user === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!password_verify(trim($plainPassword), $user->getPasswordHash())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
public function changePassword(int $userId, string $currentPassword, string $newPassword): void
|
||||
{
|
||||
$user = $this->userRepository->findById($userId);
|
||||
|
||||
if ($user === null) {
|
||||
throw new NotFoundException('Utilisateur', $userId);
|
||||
}
|
||||
|
||||
if (!password_verify(trim($currentPassword), $user->getPasswordHash())) {
|
||||
throw new \InvalidArgumentException('Mot de passe actuel incorrect');
|
||||
}
|
||||
|
||||
if (mb_strlen(trim($newPassword)) < 8) {
|
||||
throw new WeakPasswordException();
|
||||
}
|
||||
|
||||
$newHash = password_hash(trim($newPassword), PASSWORD_BCRYPT, ['cost' => 12]);
|
||||
$this->userRepository->updatePassword($userId, $newHash);
|
||||
}
|
||||
|
||||
public function isLoggedIn(): bool
|
||||
{
|
||||
return $this->sessionManager->isAuthenticated();
|
||||
}
|
||||
|
||||
public function login(User $user): void
|
||||
{
|
||||
$this->sessionManager->setUser($user->getId(), $user->getUsername(), $user->getRole());
|
||||
}
|
||||
|
||||
public function logout(): void
|
||||
{
|
||||
$this->sessionManager->destroy();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user