update
This commit is contained in:
@@ -29,6 +29,7 @@ final class AuthController
|
||||
'title' => $this->translator->get('auth.login.title'),
|
||||
'errorMessage' => Flash::get('error'),
|
||||
'oldEmail' => (string) Flash::get('old_email', ''),
|
||||
'oldRemember' => (bool) Flash::get('old_remember', false),
|
||||
'csrfToken' => Csrf::token(),
|
||||
], 'layouts/auth');
|
||||
|
||||
@@ -38,9 +39,12 @@ final class AuthController
|
||||
public function login(Request $request): Response
|
||||
{
|
||||
$csrfToken = (string) $request->input('_token', '');
|
||||
$remember = (bool) $request->input('remember', false);
|
||||
|
||||
if (!Csrf::validate($csrfToken)) {
|
||||
Flash::set('error', $this->translator->get('auth.errors.csrf_expired'));
|
||||
Flash::set('old_email', (string) $request->input('email', ''));
|
||||
Flash::set('old_remember', $remember);
|
||||
return Response::redirect('/login');
|
||||
}
|
||||
|
||||
@@ -50,15 +54,24 @@ final class AuthController
|
||||
if (!filter_var($email, FILTER_VALIDATE_EMAIL) || $password === '') {
|
||||
Flash::set('error', $this->translator->get('auth.errors.invalid_credentials_format'));
|
||||
Flash::set('old_email', $email);
|
||||
Flash::set('old_remember', $remember);
|
||||
return Response::redirect('/login');
|
||||
}
|
||||
|
||||
if (!$this->auth->attempt($email, $password)) {
|
||||
Flash::set('error', $this->translator->get('auth.errors.invalid_credentials'));
|
||||
Flash::set('old_email', $email);
|
||||
Flash::set('old_remember', $remember);
|
||||
return Response::redirect('/login');
|
||||
}
|
||||
|
||||
if ($remember) {
|
||||
$user = $this->auth->user();
|
||||
if ($user !== null) {
|
||||
$this->auth->createRememberToken((int) $user['id']);
|
||||
}
|
||||
}
|
||||
|
||||
return Response::redirect('/settings/users');
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ final class AuthMiddleware
|
||||
|
||||
public function __invoke(Request $request, callable $next): Response
|
||||
{
|
||||
if (!$this->auth->check()) {
|
||||
if (!$this->auth->check() && !$this->auth->loginFromRememberToken()) {
|
||||
return Response::redirect('/login');
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ use App\Modules\Users\UserRepository;
|
||||
final class AuthService
|
||||
{
|
||||
private const SESSION_USER_KEY = 'auth_user';
|
||||
private const REMEMBER_COOKIE = 'remember_token';
|
||||
private const REMEMBER_DAYS = 30;
|
||||
|
||||
public function __construct(private readonly UserRepository $users)
|
||||
{
|
||||
@@ -57,9 +59,69 @@ final class AuthService
|
||||
return $user;
|
||||
}
|
||||
|
||||
public function createRememberToken(int $userId): void
|
||||
{
|
||||
$token = bin2hex(random_bytes(32));
|
||||
$this->users->updateRememberToken($userId, hash('sha256', $token));
|
||||
|
||||
$secure = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off';
|
||||
setcookie(self::REMEMBER_COOKIE, $token, [
|
||||
'expires' => time() + (self::REMEMBER_DAYS * 86400),
|
||||
'path' => '/',
|
||||
'httponly' => true,
|
||||
'secure' => $secure,
|
||||
'samesite' => 'Lax',
|
||||
]);
|
||||
}
|
||||
|
||||
public function loginFromRememberToken(): bool
|
||||
{
|
||||
$cookieToken = $_COOKIE[self::REMEMBER_COOKIE] ?? '';
|
||||
if ($cookieToken === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
$tokenHash = hash('sha256', $cookieToken);
|
||||
$user = $this->users->findByRememberToken($tokenHash);
|
||||
if ($user === null) {
|
||||
$this->clearRememberCookie();
|
||||
return false;
|
||||
}
|
||||
|
||||
Session::regenerate();
|
||||
|
||||
$_SESSION[self::SESSION_USER_KEY] = [
|
||||
'id' => (int) $user['id'],
|
||||
'name' => (string) $user['name'],
|
||||
'email' => (string) $user['email'],
|
||||
'login_at' => date(DATE_ATOM),
|
||||
];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function logout(): void
|
||||
{
|
||||
$user = $this->user();
|
||||
if ($user !== null) {
|
||||
$this->users->updateRememberToken((int) $user['id'], null);
|
||||
}
|
||||
$this->clearRememberCookie();
|
||||
|
||||
unset($_SESSION[self::SESSION_USER_KEY]);
|
||||
Session::regenerate();
|
||||
}
|
||||
|
||||
private function clearRememberCookie(): void
|
||||
{
|
||||
$secure = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off';
|
||||
setcookie(self::REMEMBER_COOKIE, '', [
|
||||
'expires' => time() - 3600,
|
||||
'path' => '/',
|
||||
'httponly' => true,
|
||||
'secure' => $secure,
|
||||
'samesite' => 'Lax',
|
||||
]);
|
||||
unset($_COOKIE[self::REMEMBER_COOKIE]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user