2
0
Web/auth/Auth.php
2025-09-11 10:35:42 -05:00

229 lines
4.8 KiB
PHP

<?php
require_once __DIR__ . '/User.php';
require_once __DIR__ . '/../Session.php';
require_once __DIR__ . '/../Cookies.php';
/**
* Simplified Auth handles user authentication with external verification
*/
class Auth
{
private Session $session;
private Cookies $cookie;
private ?User $user = null;
private array $config;
const SESSION_KEY = 'auth_user_data';
const REMEMBER_COOKIE = 'remember_token';
const REMEMBER_DURATION = 2592000; // 30 days in seconds
public function __construct(Session $session, ?Cookie $cookie = null, array $config = [])
{
$this->session = $session;
$this->cookie = $cookie ?: new Cookies([
'path' => '/',
'httponly' => true,
'samesite' => 'Lax'
]);
$this->config = array_merge([
'cookie_name' => self::REMEMBER_COOKIE,
'cookie_lifetime' => self::REMEMBER_DURATION
], $config);
$this->initializeFromSession();
}
/**
* Login with externally verified user data
*/
public function login(array $userData, bool $remember = false): void
{
$this->user = new User($userData);
$this->session->set(self::SESSION_KEY, $userData);
$this->session->regenerate();
if ($remember) $this->createRememberToken($userData);
}
/**
* Login using user data directly
*/
public function loginUser(User $user, bool $remember = false): void
{
$this->user = $user;
$this->session->set(self::SESSION_KEY, $user->toArray());
$this->session->regenerate();
if ($remember) $this->createRememberToken($user->toArray());
}
/**
* Logout the current user
*/
public function logout(): void
{
$this->user = null;
$this->session->remove(self::SESSION_KEY);
$this->session->regenerate();
$this->clearRememberCookie();
}
/**
* Check if user is authenticated
*/
public function check(): bool
{
return $this->user() !== null;
}
/**
* Check if user is guest (not authenticated)
*/
public function guest(): bool
{
return !$this->check();
}
/**
* Get the currently authenticated user
*/
public function user(): ?User
{
if ($this->user) return $this->user;
// Try to load from session
$userData = $this->session->get(self::SESSION_KEY);
if ($userData) {
$this->user = new User($userData);
return $this->user;
}
// Try to load from remember cookie
$userData = $this->getUserDataFromRememberCookie();
if ($userData) {
$this->user = new User($userData);
$this->session->set(self::SESSION_KEY, $userData);
}
return $this->user;
}
/**
* Get user ID
*/
public function id(): int|string|null
{
return $this->user()?->getId();
}
/**
* Set user data after external verification
*/
public function setUserData(array $userData): void
{
$this->user = new User($userData);
$this->session->set(self::SESSION_KEY, $userData);
}
/**
* Hash a password
*/
public function hashPassword(string $password): string
{
return password_hash($password, PASSWORD_BCRYPT, ['cost' => 10]);
}
/**
* Verify a password against hash
*/
public function verifyPassword(string $password, string $hash): bool
{
return password_verify($password, $hash);
}
/**
* Initialize user from session
*/
private function initializeFromSession(): void
{
$this->session->start();
$this->user();
}
/**
* Create remember token for user
*/
private function createRememberToken(array $userData): void
{
$token = $this->generateRememberToken();
$hashedToken = hash('sha256', $token);
$userData['remember_token'] = $hashedToken;
$this->session->set('remember_user_data', $userData);
$this->setRememberCookie($userData['id'] . '|' . $token);
}
/**
* Generate a random remember token
*/
private function generateRememberToken(): string
{
return bin2hex(random_bytes(32));
}
/**
* Set remember cookie
*/
private function setRememberCookie(string $value): void
{
$this->cookie->setWithLifetime(
$this->config['cookie_name'],
$value,
$this->config['cookie_lifetime']
);
}
/**
* Clear remember cookie
*/
private function clearRememberCookie(): void
{
$this->cookie->delete($this->config['cookie_name']);
}
/**
* Get user data from remember cookie
*/
private function getUserDataFromRememberCookie(): ?array
{
$cookie = $this->cookie->get($this->config['cookie_name']);
if (!$cookie || !str_contains($cookie, '|')) return null;
[$id, $token] = explode('|', $cookie, 2);
$hashedToken = hash('sha256', $token);
$userData = $this->session->get('remember_user_data');
if (!$userData || $userData['id'] != $id || ($userData['remember_token'] ?? null) !== $hashedToken) {
$this->clearRememberCookie();
return null;
}
return $userData;
}
/**
* Clear user data and session
*/
public function clear(): void
{
$this->user = null;
$this->session->remove(self::SESSION_KEY);
$this->session->remove('remember_user_data');
$this->clearRememberCookie();
}
}