227 lines
4.7 KiB
PHP
227 lines
4.7 KiB
PHP
<?php
|
|
|
|
namespace Web;
|
|
|
|
/**
|
|
* 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, ?Cookies $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();
|
|
}
|
|
}
|