From 0c40ae5888c3f9c0a43a2c37816bc5d2caadbf48 Mon Sep 17 00:00:00 2001 From: Sky Johnson Date: Thu, 11 Sep 2025 08:23:31 -0500 Subject: [PATCH] heavily simplify auth --- auth/Auth.php | 153 ++++++------------- auth/AuthMiddleware.php | 14 +- auth/User.php | 57 +++---- auth/UserProviderInterface.php | 52 ------- auth/providers/JsonUserProvider.php | 170 --------------------- auth/providers/MysqlUserProvider.php | 205 ------------------------- auth/providers/SqliteUserProvider.php | 190 ----------------------- example-auth.php | 210 -------------------------- 8 files changed, 72 insertions(+), 979 deletions(-) delete mode 100644 auth/UserProviderInterface.php delete mode 100644 auth/providers/JsonUserProvider.php delete mode 100644 auth/providers/MysqlUserProvider.php delete mode 100644 auth/providers/SqliteUserProvider.php delete mode 100644 example-auth.php diff --git a/auth/Auth.php b/auth/Auth.php index 7aa2e7a..81b96f2 100644 --- a/auth/Auth.php +++ b/auth/Auth.php @@ -1,26 +1,23 @@ provider = $provider; $this->session = $session; $this->config = array_merge([ 'cookie_name' => self::REMEMBER_COOKIE, @@ -36,54 +33,31 @@ class Auth } /** - * Attempt to authenticate user with credentials + * Login with externally verified user data */ - public function attempt(array $credentials, bool $remember = false): bool + public function login(array $userData, bool $remember = false): void { - $identifier = $credentials['email'] ?? $credentials['username'] ?? null; - $password = $credentials['password'] ?? null; - - if (!$identifier || !$password) { - return false; - } - - $user = $this->provider->findByCredentials($identifier); - - if (!$user || !$this->provider->verifyPassword($user, $password)) { - return false; - } - - $this->login($user, $remember); - return true; - } - - /** - * Login a user instance - */ - public function login(User $user, bool $remember = false): void - { - $this->user = $user; - $this->session->set(self::SESSION_KEY, $user->getId()); + $this->user = new User($userData); + $this->session->set(self::SESSION_KEY, $userData); $this->session->regenerate(); if ($remember) { - $this->createRememberToken($user); + $this->createRememberToken($userData); } } /** - * Login using user ID + * Login using user data directly */ - public function loginById(int|string $id, bool $remember = false): bool + public function loginUser(User $user, bool $remember = false): void { - $user = $this->provider->findById($id); + $this->user = $user; + $this->session->set(self::SESSION_KEY, $user->toArray()); + $this->session->regenerate(); - if (!$user) { - return false; + if ($remember) { + $this->createRememberToken($user->toArray()); } - - $this->login($user, $remember); - return true; } /** @@ -91,10 +65,6 @@ class Auth */ public function logout(): void { - if ($this->user && $this->user->rememberToken) { - $this->provider->updateRememberToken($this->user, null); - } - $this->user = null; $this->session->remove(self::SESSION_KEY); $this->session->regenerate(); @@ -127,16 +97,17 @@ class Auth } // Try to load from session - $userId = $this->session->get(self::SESSION_KEY); - if ($userId) { - $this->user = $this->provider->findById($userId); + $userData = $this->session->get(self::SESSION_KEY); + if ($userData) { + $this->user = new User($userData); return $this->user; } // Try to load from remember cookie - $this->user = $this->getUserFromRememberCookie(); - if ($this->user) { - $this->session->set(self::SESSION_KEY, $this->user->getId()); + $userData = $this->getUserDataFromRememberCookie(); + if ($userData) { + $this->user = new User($userData); + $this->session->set(self::SESSION_KEY, $userData); } return $this->user; @@ -151,39 +122,12 @@ class Auth } /** - * Register a new user + * Set user data after external verification */ - public function register(array $data, bool $login = true): User + public function setUserData(array $userData): void { - // Hash password before storing - if (isset($data['password'])) { - $data['password'] = $this->hashPassword($data['password']); - } - - $user = $this->provider->create($data); - - if ($login) { - $this->login($user); - } - - return $user; - } - - /** - * Validate user credentials without logging in - */ - public function validate(array $credentials): bool - { - $identifier = $credentials['email'] ?? $credentials['username'] ?? null; - $password = $credentials['password'] ?? null; - - if (!$identifier || !$password) { - return false; - } - - $user = $this->provider->findByCredentials($identifier); - - return $user && $this->provider->verifyPassword($user, $password); + $this->user = new User($userData); + $this->session->set(self::SESSION_KEY, $userData); } /** @@ -207,25 +151,22 @@ class Auth */ private function initializeFromSession(): void { - if (!$this->session->isStarted()) { - $this->session->start(); - } - + $this->session->start(); $this->user(); } /** * Create remember token for user */ - private function createRememberToken(User $user): void + 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->provider->updateRememberToken($user, $hashedToken); - $user->rememberToken = $hashedToken; - - $this->setRememberCookie($user->getId() . '|' . $token); + $this->setRememberCookie($userData['id'] . '|' . $token); } /** @@ -275,9 +216,9 @@ class Auth } /** - * Get user from remember cookie + * Get user data from remember cookie */ - private function getUserFromRememberCookie(): ?User + private function getUserDataFromRememberCookie(): ?array { $cookie = $_COOKIE[$this->config['cookie_name']] ?? null; @@ -288,32 +229,24 @@ class Auth [$id, $token] = explode('|', $cookie, 2); $hashedToken = hash('sha256', $token); - $user = $this->provider->findById($id); + $userData = $this->session->get('remember_user_data'); - if (!$user || $user->rememberToken !== $hashedToken) { + if (!$userData || $userData['id'] != $id || ($userData['remember_token'] ?? null) !== $hashedToken) { $this->clearRememberCookie(); return null; } - return $user; + return $userData; } /** - * Refresh user instance from provider + * Clear user data and session */ - public function refresh(): void + public function clear(): void { - if ($this->user) { - $this->user = $this->provider->findById($this->user->getId()); - } - } - - /** - * Set the current user - */ - public function setUser(User $user): void - { - $this->user = $user; - $this->session->set(self::SESSION_KEY, $user->getId()); + $this->user = null; + $this->session->remove(self::SESSION_KEY); + $this->session->remove('remember_user_data'); + $this->clearRememberCookie(); } } \ No newline at end of file diff --git a/auth/AuthMiddleware.php b/auth/AuthMiddleware.php index c383b20..a332779 100644 --- a/auth/AuthMiddleware.php +++ b/auth/AuthMiddleware.php @@ -66,9 +66,7 @@ class AuthMiddleware public function optional(): callable { return function(Context $context, callable $next) { - if ($this->auth->check()) { - $context->set('user', $this->auth->user()); - } + if ($this->auth->check()) $context->set('user', $this->auth->user()); $next(); }; } @@ -91,7 +89,7 @@ class AuthMiddleware } $user = $this->auth->user(); - $userRole = $user->getAttribute('role') ?? $user->role ?? null; + $userRole = $user->role; if (!in_array($userRole, $roles)) { if ($context->request->expectsJson()) { @@ -174,7 +172,7 @@ class AuthMiddleware ?? $context->request->header('X-CSRF-TOKEN') ?? $context->request->header('X-XSRF-TOKEN'); - if (!$context->session->validateToken($token)) { + if (!$context->session->validateCsrf($token)) { if ($context->request->expectsJson()) { $context->json(['error' => 'CSRF token mismatch'], 419); return; @@ -195,12 +193,12 @@ class AuthMiddleware return function(Context $context, callable $next) { // Auth class already handles remember cookies in constructor // This middleware can be used to refresh the remember token if needed - + if ($this->auth->check()) { $context->set('user', $this->auth->user()); } - + $next(); }; } -} \ No newline at end of file +} diff --git a/auth/User.php b/auth/User.php index d34e5d9..d350e75 100644 --- a/auth/User.php +++ b/auth/User.php @@ -1,7 +1,7 @@ $value) { - if (property_exists($this, $key)) { - $this->$key = $value; - } else { - $this->attributes[$key] = $value; - } - } + $this->id = $data['id'] ?? 0; + $this->username = $data['username'] ?? ''; + $this->email = $data['email'] ?? ''; + $this->password = $data['password'] ?? ''; + $this->rememberToken = $data['remember_token'] ?? $data['rememberToken'] ?? null; + $this->role = $data['role'] ?? 'user'; + $this->lastLogin = $data['last_login'] ?? $data['lastLogin'] ?? null; } /** @@ -41,22 +40,6 @@ class User return $this->id; } - /** - * Get custom attribute - */ - public function getAttribute(string $key): mixed - { - return $this->attributes[$key] ?? null; - } - - /** - * Set custom attribute - */ - public function setAttribute(string $key, mixed $value): void - { - $this->attributes[$key] = $value; - } - /** * Convert to array */ @@ -66,9 +49,11 @@ class User 'id' => $this->id, 'username' => $this->username, 'email' => $this->email, - 'created_at' => $this->createdAt, - 'updated_at' => $this->updatedAt, - ] + $this->attributes; + 'password' => $this->password, + 'remember_token' => $this->rememberToken, + 'role' => $this->role, + 'last_login' => $this->lastLogin, + ]; } /** @@ -76,8 +61,12 @@ class User */ public function toSafeArray(): array { - $data = $this->toArray(); - unset($data['password'], $data['remember_token']); - return $data; + return [ + 'id' => $this->id, + 'username' => $this->username, + 'email' => $this->email, + 'role' => $this->role, + 'last_login' => $this->lastLogin, + ]; } -} \ No newline at end of file +} diff --git a/auth/UserProviderInterface.php b/auth/UserProviderInterface.php deleted file mode 100644 index 25ecef5..0000000 --- a/auth/UserProviderInterface.php +++ /dev/null @@ -1,52 +0,0 @@ -filePath = $filePath; - $this->loadUsers(); - } - - /** - * Load users from JSON file - */ - private function loadUsers(): void - { - if (!file_exists($this->filePath)) { - $this->users = []; - $this->saveUsers(); - return; - } - - $content = file_get_contents($this->filePath); - $data = json_decode($content, true) ?? []; - - $this->users = []; - foreach ($data as $userData) { - $this->users[$userData['id']] = new User($userData); - } - } - - /** - * Save users to JSON file - */ - private function saveUsers(): void - { - $data = []; - foreach ($this->users as $user) { - $userData = [ - 'id' => $user->id, - 'username' => $user->username, - 'email' => $user->email, - 'password' => $user->password, - 'remember_token' => $user->rememberToken, - 'created_at' => $user->createdAt, - 'updated_at' => $user->updatedAt, - ] + $user->attributes; - $data[] = $userData; - } - - file_put_contents($this->filePath, json_encode($data, JSON_PRETTY_PRINT)); - } - - /** - * Generate next user ID - */ - private function generateId(): int - { - if (empty($this->users)) { - return 1; - } - return max(array_keys($this->users)) + 1; - } - - public function findById(int|string $id): ?User - { - return $this->users[$id] ?? null; - } - - public function findByEmail(string $email): ?User - { - foreach ($this->users as $user) { - if ($user->email === $email) { - return $user; - } - } - return null; - } - - public function findByUsername(string $username): ?User - { - foreach ($this->users as $user) { - if ($user->username === $username) { - return $user; - } - } - return null; - } - - public function findByCredentials(string $identifier): ?User - { - // Check if identifier is email - if (filter_var($identifier, FILTER_VALIDATE_EMAIL)) { - return $this->findByEmail($identifier); - } - - // Otherwise treat as username - return $this->findByUsername($identifier); - } - - public function findByRememberToken(string $token): ?User - { - foreach ($this->users as $user) { - if ($user->rememberToken === $token) { - return $user; - } - } - return null; - } - - public function create(array $data): User - { - $data['id'] = $data['id'] ?? $this->generateId(); - $data['created_at'] = $data['created_at'] ?? date('Y-m-d H:i:s'); - $data['updated_at'] = $data['updated_at'] ?? date('Y-m-d H:i:s'); - - $user = new User($data); - $this->users[$user->id] = $user; - $this->saveUsers(); - - return $user; - } - - public function update(User $user, array $data): bool - { - if (!isset($this->users[$user->id])) { - return false; - } - - foreach ($data as $key => $value) { - if (property_exists($user, $key)) { - $user->$key = $value; - } else { - $user->attributes[$key] = $value; - } - } - - $user->updatedAt = date('Y-m-d H:i:s'); - $this->users[$user->id] = $user; - $this->saveUsers(); - - return true; - } - - public function updateRememberToken(User $user, ?string $token): bool - { - if (!isset($this->users[$user->id])) { - return false; - } - - $user->rememberToken = $token; - $this->users[$user->id] = $user; - $this->saveUsers(); - - return true; - } - - public function verifyPassword(User $user, string $password): bool - { - return password_verify($password, $user->password); - } -} \ No newline at end of file diff --git a/auth/providers/MysqlUserProvider.php b/auth/providers/MysqlUserProvider.php deleted file mode 100644 index e8a86d1..0000000 --- a/auth/providers/MysqlUserProvider.php +++ /dev/null @@ -1,205 +0,0 @@ -table = $table; - - $dsn = sprintf( - 'mysql:host=%s;port=%s;dbname=%s;charset=%s', - $config['host'] ?? 'localhost', - $config['port'] ?? 3306, - $config['database'], - $config['charset'] ?? 'utf8mb4' - ); - - try { - $this->db = new PDO( - $dsn, - $config['username'], - $config['password'], - [ - PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, - PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, - PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4" - ] - ); - $this->createTable(); - } catch (PDOException $e) { - throw new Exception("Failed to connect to MySQL database: " . $e->getMessage()); - } - } - - /** - * Create users table if it doesn't exist - */ - private function createTable(): void - { - $sql = "CREATE TABLE IF NOT EXISTS {$this->table} ( - id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, - username VARCHAR(255) UNIQUE, - email VARCHAR(255) UNIQUE, - password VARCHAR(255) NOT NULL, - remember_token VARCHAR(255), - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - attributes JSON, - INDEX idx_email (email), - INDEX idx_username (username), - INDEX idx_remember_token (remember_token) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"; - - $this->db->exec($sql); - } - - /** - * Map database row to User object - */ - private function mapToUser(array $row): User - { - $attributes = isset($row['attributes']) ? json_decode($row['attributes'], true) ?? [] : []; - - return new User([ - 'id' => $row['id'], - 'username' => $row['username'], - 'email' => $row['email'], - 'password' => $row['password'], - 'rememberToken' => $row['remember_token'], - 'createdAt' => $row['created_at'], - 'updatedAt' => $row['updated_at'], - 'attributes' => $attributes - ]); - } - - public function findById(int|string $id): ?User - { - $stmt = $this->db->prepare("SELECT * FROM {$this->table} WHERE id = :id"); - $stmt->execute(['id' => $id]); - - $row = $stmt->fetch(); - return $row ? $this->mapToUser($row) : null; - } - - public function findByEmail(string $email): ?User - { - $stmt = $this->db->prepare("SELECT * FROM {$this->table} WHERE email = :email"); - $stmt->execute(['email' => $email]); - - $row = $stmt->fetch(); - return $row ? $this->mapToUser($row) : null; - } - - public function findByUsername(string $username): ?User - { - $stmt = $this->db->prepare("SELECT * FROM {$this->table} WHERE username = :username"); - $stmt->execute(['username' => $username]); - - $row = $stmt->fetch(); - return $row ? $this->mapToUser($row) : null; - } - - public function findByCredentials(string $identifier): ?User - { - $stmt = $this->db->prepare( - "SELECT * FROM {$this->table} WHERE email = :identifier OR username = :identifier" - ); - $stmt->execute(['identifier' => $identifier]); - - $row = $stmt->fetch(); - return $row ? $this->mapToUser($row) : null; - } - - public function findByRememberToken(string $token): ?User - { - $stmt = $this->db->prepare("SELECT * FROM {$this->table} WHERE remember_token = :token"); - $stmt->execute(['token' => $token]); - - $row = $stmt->fetch(); - return $row ? $this->mapToUser($row) : null; - } - - public function create(array $data): User - { - $attributes = $data['attributes'] ?? []; - unset($data['attributes']); - - $stmt = $this->db->prepare( - "INSERT INTO {$this->table} (username, email, password, remember_token, attributes) - VALUES (:username, :email, :password, :remember_token, :attributes)" - ); - - $stmt->execute([ - 'username' => $data['username'] ?? null, - 'email' => $data['email'] ?? null, - 'password' => $data['password'], - 'remember_token' => $data['remember_token'] ?? null, - 'attributes' => json_encode($attributes) - ]); - - $data['id'] = $this->db->lastInsertId(); - $data['attributes'] = $attributes; - - // Fetch created/updated timestamps - $user = $this->findById($data['id']); - return $user; - } - - public function update(User $user, array $data): bool - { - $attributes = array_merge($user->attributes, $data['attributes'] ?? []); - unset($data['attributes']); - - $fields = []; - $params = ['id' => $user->id]; - - foreach (['username', 'email', 'password'] as $field) { - if (isset($data[$field])) { - $fields[] = "$field = :$field"; - $params[$field] = $data[$field]; - $user->$field = $data[$field]; - } - } - - if (!empty($attributes)) { - $fields[] = "attributes = :attributes"; - $params['attributes'] = json_encode($attributes); - $user->attributes = $attributes; - } - - if (empty($fields)) { - return true; - } - - $sql = "UPDATE {$this->table} SET " . implode(', ', $fields) . " WHERE id = :id"; - $stmt = $this->db->prepare($sql); - - return $stmt->execute($params); - } - - public function updateRememberToken(User $user, ?string $token): bool - { - $stmt = $this->db->prepare( - "UPDATE {$this->table} SET remember_token = :token WHERE id = :id" - ); - - return $stmt->execute([ - 'id' => $user->id, - 'token' => $token - ]); - } - - public function verifyPassword(User $user, string $password): bool - { - return password_verify($password, $user->password); - } -} \ No newline at end of file diff --git a/auth/providers/SqliteUserProvider.php b/auth/providers/SqliteUserProvider.php deleted file mode 100644 index 0faf24a..0000000 --- a/auth/providers/SqliteUserProvider.php +++ /dev/null @@ -1,190 +0,0 @@ -table = $table; - - try { - $this->db = new PDO("sqlite:$databasePath"); - $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); - $this->createTable(); - } catch (PDOException $e) { - throw new Exception("Failed to connect to SQLite database: " . $e->getMessage()); - } - } - - /** - * Create users table if it doesn't exist - */ - private function createTable(): void - { - $sql = "CREATE TABLE IF NOT EXISTS {$this->table} ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - username VARCHAR(255) UNIQUE, - email VARCHAR(255) UNIQUE, - password VARCHAR(255) NOT NULL, - remember_token VARCHAR(255), - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, - attributes TEXT - )"; - - $this->db->exec($sql); - } - - /** - * Map database row to User object - */ - private function mapToUser(array $row): User - { - $attributes = isset($row['attributes']) ? json_decode($row['attributes'], true) ?? [] : []; - - return new User([ - 'id' => $row['id'], - 'username' => $row['username'], - 'email' => $row['email'], - 'password' => $row['password'], - 'rememberToken' => $row['remember_token'], - 'createdAt' => $row['created_at'], - 'updatedAt' => $row['updated_at'], - 'attributes' => $attributes - ]); - } - - public function findById(int|string $id): ?User - { - $stmt = $this->db->prepare("SELECT * FROM {$this->table} WHERE id = :id"); - $stmt->execute(['id' => $id]); - - $row = $stmt->fetch(PDO::FETCH_ASSOC); - return $row ? $this->mapToUser($row) : null; - } - - public function findByEmail(string $email): ?User - { - $stmt = $this->db->prepare("SELECT * FROM {$this->table} WHERE email = :email"); - $stmt->execute(['email' => $email]); - - $row = $stmt->fetch(PDO::FETCH_ASSOC); - return $row ? $this->mapToUser($row) : null; - } - - public function findByUsername(string $username): ?User - { - $stmt = $this->db->prepare("SELECT * FROM {$this->table} WHERE username = :username"); - $stmt->execute(['username' => $username]); - - $row = $stmt->fetch(PDO::FETCH_ASSOC); - return $row ? $this->mapToUser($row) : null; - } - - public function findByCredentials(string $identifier): ?User - { - $stmt = $this->db->prepare( - "SELECT * FROM {$this->table} WHERE email = :identifier OR username = :identifier" - ); - $stmt->execute(['identifier' => $identifier]); - - $row = $stmt->fetch(PDO::FETCH_ASSOC); - return $row ? $this->mapToUser($row) : null; - } - - public function findByRememberToken(string $token): ?User - { - $stmt = $this->db->prepare("SELECT * FROM {$this->table} WHERE remember_token = :token"); - $stmt->execute(['token' => $token]); - - $row = $stmt->fetch(PDO::FETCH_ASSOC); - return $row ? $this->mapToUser($row) : null; - } - - public function create(array $data): User - { - $attributes = $data['attributes'] ?? []; - unset($data['attributes']); - - $stmt = $this->db->prepare( - "INSERT INTO {$this->table} (username, email, password, remember_token, attributes, created_at, updated_at) - VALUES (:username, :email, :password, :remember_token, :attributes, :created_at, :updated_at)" - ); - - $stmt->execute([ - 'username' => $data['username'] ?? null, - 'email' => $data['email'] ?? null, - 'password' => $data['password'], - 'remember_token' => $data['remember_token'] ?? null, - 'attributes' => json_encode($attributes), - 'created_at' => $data['created_at'] ?? date('Y-m-d H:i:s'), - 'updated_at' => $data['updated_at'] ?? date('Y-m-d H:i:s') - ]); - - $data['id'] = $this->db->lastInsertId(); - $data['attributes'] = $attributes; - - return new User($data); - } - - public function update(User $user, array $data): bool - { - $attributes = array_merge($user->attributes, $data['attributes'] ?? []); - unset($data['attributes']); - - $fields = []; - $params = ['id' => $user->id]; - - foreach (['username', 'email', 'password'] as $field) { - if (isset($data[$field])) { - $fields[] = "$field = :$field"; - $params[$field] = $data[$field]; - $user->$field = $data[$field]; - } - } - - if (!empty($attributes)) { - $fields[] = "attributes = :attributes"; - $params['attributes'] = json_encode($attributes); - $user->attributes = $attributes; - } - - if (empty($fields)) { - return true; - } - - $fields[] = "updated_at = :updated_at"; - $params['updated_at'] = date('Y-m-d H:i:s'); - - $sql = "UPDATE {$this->table} SET " . implode(', ', $fields) . " WHERE id = :id"; - $stmt = $this->db->prepare($sql); - - return $stmt->execute($params); - } - - public function updateRememberToken(User $user, ?string $token): bool - { - $stmt = $this->db->prepare( - "UPDATE {$this->table} SET remember_token = :token, updated_at = :updated_at WHERE id = :id" - ); - - return $stmt->execute([ - 'id' => $user->id, - 'token' => $token, - 'updated_at' => date('Y-m-d H:i:s') - ]); - } - - public function verifyPassword(User $user, string $password): bool - { - return password_verify($password, $user->password); - } -} \ No newline at end of file diff --git a/example-auth.php b/example-auth.php deleted file mode 100644 index f9fc06c..0000000 --- a/example-auth.php +++ /dev/null @@ -1,210 +0,0 @@ - 'localhost', -// 'database' => 'myapp', -// 'username' => 'root', -// 'password' => 'password' -// ]); - -// Create web application -$app = new Web(debug: true); - -// Initialize auth system -$auth = new Auth($userProvider, new Session()); -$authMiddleware = new AuthMiddleware($auth); - -// Make auth available in all routes -$app->use(function($context, $next) use ($auth) { - $context->set('auth', $auth); - $next(); -}); - -// Public routes -$app->get('/', function($context) { - $user = $context->get('auth')->user(); - $context->html("

Welcome " . ($user ? $user->username : 'Guest') . "

"); -}); - -// Registration page -$app->get('/register', function($context) { - $csrfToken = $context->session->token(); - $context->html(<< - -
-
-
-
- - - HTML); -}); - -// Registration handler -$app->post('/register', function($context) use ($auth) { - // Validate input - $validator = $context->validate($context->request->all(), [ - 'username' => 'required|alphaNum|min:3|max:20', - 'email' => 'required|email', - 'password' => 'required|min:6|confirmed' - ]); - - // Check if username/email already exists - if ($auth->provider->findByUsername($context->request->input('username'))) { - $context->error(400, 'Username already taken'); - return; - } - - if ($auth->provider->findByEmail($context->request->input('email'))) { - $context->error(400, 'Email already registered'); - return; - } - - // Register user - $user = $auth->register([ - 'username' => $context->request->input('username'), - 'email' => $context->request->input('email'), - 'password' => $context->request->input('password') - ]); - - $context->redirect('/dashboard'); -})->use($authMiddleware->verifyCsrf()); - -// Login page -$app->get('/login', function($context) { - $csrfToken = $context->session->token(); - $context->html(<< - -
-
-
- - - HTML); -})->use($authMiddleware->requireGuest()); - -// Login handler -$app->post('/login', function($context) use ($auth) { - $credentials = [ - 'username' => $context->request->input('username'), - 'password' => $context->request->input('password') - ]; - - $remember = $context->request->input('remember') === 'on'; - - if ($auth->attempt($credentials, $remember)) { - $context->redirect('/dashboard'); - } else { - $context->error(401, 'Invalid credentials'); - } -})->use($authMiddleware->verifyCsrf()) - ->use($authMiddleware->requireGuest()); - -// Logout -$app->post('/logout', function($context) use ($auth) { - $auth->logout(); - $context->redirect('/'); -})->use($authMiddleware->verifyCsrf()); - -// Protected routes -$app->group('/dashboard', function($app) use ($authMiddleware) { - // Apply auth middleware to all routes in this group - $app->use($authMiddleware->requireAuth()); - - $app->get('', function($context) { - $user = $context->get('user'); - $csrfToken = $context->session->token(); - $context->html(<<Dashboard -

Welcome, {$user->username}!

-

Email: {$user->email}

-
- - -
- HTML); - }); - - $app->get('/profile', function($context) { - $user = $context->get('user'); - $context->json($user->toSafeArray()); - }); - - $app->post('/update-profile', function($context) use ($auth) { - $user = $context->get('user'); - - $validator = $context->validate($context->request->all(), [ - 'email' => 'email', - 'username' => 'alphaNum|min:3|max:20' - ]); - - $data = $context->request->only(['email', 'username']); - - if (!empty($data)) { - $auth->provider->update($user, $data); - $auth->refresh(); - } - - $context->json(['success' => true, 'user' => $auth->user()->toSafeArray()]); - })->use($authMiddleware->verifyCsrf()); -}); - -// Admin only routes -$app->group('/admin', function($app) use ($authMiddleware) { - // Require admin role - $app->use($authMiddleware->requireRole('admin')); - - $app->get('', function($context) { - $context->html('

Admin Panel

'); - }); -}); - -// API routes with rate limiting -$app->group('/api', function($app) use ($authMiddleware, $auth) { - // Optional auth for API - $app->use($authMiddleware->optional()); - - // Rate limiting: 60 requests per minute - $app->use($authMiddleware->rateLimit(60, 1)); - - $app->post('/login', function($context) use ($auth) { - $credentials = $context->request->only(['username', 'password']); - - if ($auth->validate($credentials)) { - $auth->attempt($credentials); - return ['success' => true, 'user' => $auth->user()->toSafeArray()]; - } - - return $context->json(['error' => 'Invalid credentials'], 401); - }); - - $app->get('/me', function($context) use ($auth) { - if ($auth->guest()) { - return $context->json(['error' => 'Unauthenticated'], 401); - } - - return $auth->user()->toSafeArray(); - }); -}); - -// Run the application -$app->run(); \ No newline at end of file