Auth: reemplazar Basic Auth por sesión PHP con login propio

- login.html: página de acceso con diseño Quiet Wealth (sin popup del browser)
- api/login.php: endpoint POST para iniciar sesión, GET ?action=logout para cerrarla
- auth.php: valida sesión PHP ($_SESSION) en lugar de HTTP Basic Auth
- ui.js: apiFetch() intercepta 401 y redirige a login.html automáticamente
- Todos los fetch() en dashboard, add y historial migrados a apiFetch()
- Eliminado docker/htpasswd y auth_basic de NGINX

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Ricardo Monla
2026-06-03 16:25:50 -03:00
co-authored by Claude Sonnet 4.6
parent 1244235820
commit ead1bf8ffc
10 changed files with 176 additions and 19 deletions
+2 -2
View File
@@ -13,7 +13,7 @@ document.addEventListener('DOMContentLoaded', () => {
iptFecha.valueAsDate = new Date();
// Cargar categorías desde la API
fetch('api/movimientos.php')
apiFetch('api/movimientos.php')
.then(r => r.json())
.then(data => {
if (data.categorias) {
@@ -98,7 +98,7 @@ document.addEventListener('DOMContentLoaded', () => {
btnSave.innerHTML = 'Guardando...';
btnSave.disabled = true;
const r = await fetch('api/movimientos.php', {
const r = await apiFetch('api/movimientos.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
+1 -1
View File
@@ -1,6 +1,6 @@
document.addEventListener('DOMContentLoaded', async () => {
try {
const response = await fetch('api/movimientos.php');
const response = await apiFetch('api/movimientos.php');
const data = await response.json();
if (data.status === 'success') {
+2 -2
View File
@@ -8,7 +8,7 @@ async function cargarHistorial() {
const lista = document.getElementById('ui-lista');
try {
const r = await fetch('api/movimientos.php?view=historial');
const r = await apiFetch('api/movimientos.php?view=historial');
const data = await r.json();
loading.classList.add('hidden');
@@ -83,7 +83,7 @@ async function eliminar(id, titulo) {
if (!ok) return;
try {
const r = await fetch('api/movimientos.php', {
const r = await apiFetch('api/movimientos.php', {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id: parseInt(id) })
+10
View File
@@ -1,3 +1,13 @@
// Wrapper de fetch que redirige al login si la sesión expiró
window.apiFetch = async function (url, options = {}) {
const r = await fetch(url, options);
if (r.status === 401) {
window.location.href = 'login.html';
return null;
}
return r;
};
(function () {
const MODAL_HTML = `
<div id="rm-modal-overlay" class="fixed inset-0 z-[100] flex items-end justify-center p-6 bg-black/50 backdrop-blur-sm hidden">