prepare(" SELECT u.*, r.nombre as rol_nombre, i.codigo as idioma_codigo FROM usuarios u LEFT JOIN roles r ON u.rol_id = r.id LEFT JOIN idiomas i ON u.idioma_id = i.id WHERE u.username = ? AND u.activo = 1 "); $stmt->execute([$username]); $user = $stmt->fetch(); if ($user && password_verify($password, $user['password'])) { // Cargar permisos del usuario $permisos = JWTAuth::loadUserPermissions($user['id']); // Generar token JWT $token = JWTAuth::generateToken( $user['id'], $user['username'], $user['rol_nombre'] ?? 'Editor', $user['idioma_codigo'] ?? 'es', $permisos ); // Guardar token en cookie setcookie('auth_token', $token, [ 'expires' => time() + 3600, 'path' => '/', 'secure' => false, // Cambiar a true en producción con HTTPS 'httponly' => true, 'samesite' => 'Lax' ]); // Actualizar último acceso $stmt = $db->prepare("UPDATE usuarios SET ultimo_acceso = NOW() WHERE id = ?"); $stmt->execute([$user['id']]); // Redireccionar $redirect = $_GET['redirect'] ?? '/index.php'; // Validar que la redirección sea interna para evitar open redirect if (!preg_match('/^\/[a-zA-Z0-9_\-\/]+\.php(\?.*)?$/', $redirect)) { $redirect = '/index.php'; } header('Location: ' . $redirect); exit; } else { $error = 'Usuario o contraseña incorrectos'; } } catch (Exception $e) { $error = 'Error del sistema. Intente nuevamente.'; error_log('Error de login: ' . $e->getMessage()); } } } ?>