vamos2
All checks were successful
build-and-deploy / build (push) Successful in 25s
build-and-deploy / deploy (push) Successful in 4s

This commit is contained in:
2025-10-12 02:08:41 -06:00
parent 98fb972a4e
commit bca654dee4
2 changed files with 61 additions and 53 deletions

View File

@@ -36,15 +36,19 @@ const musicStore = useMusicStore()
// Check auth on mount and setup listeners // Check auth on mount and setup listeners
onMounted(async () => { onMounted(async () => {
await checkAuth(true) // Asumimos autenticado inicialmente (si la página cargó, pasamos Authentik)
// Solo verificamos para confirmar
await checkAuth(false)
setupVisibilityListener() setupVisibilityListener()
// Chequea auth cada 30 segundos mientras la pestaña está activa // Polling más inteligente: solo si estamos autenticados
const interval = setInterval(() => { const interval = setInterval(() => {
if (!document.hidden) { if (!document.hidden && isAuthenticated.value) {
checkAuth() // Solo hace polling si creemos estar autenticados
// Evita spam de requests cuando ya sabemos que no estamos autenticados
checkAuth(false)
} }
}, 30000) }, 60000) // 60 segundos (menos agresivo)
onUnmounted(() => { onUnmounted(() => {
clearInterval(interval) clearInterval(interval)
@@ -104,9 +108,9 @@ const statusText = computed(() => {
case 'authenticated': case 'authenticated':
return 'Conectado' return 'Conectado'
case 'unauthenticated': case 'unauthenticated':
return 'Sin conexión' return 'Reautenticar'
default: default:
return 'Desconocido' return 'Verificando...'
} }
}) })
@@ -115,11 +119,11 @@ const tooltipText = computed(() => {
switch (authStatus.value) { switch (authStatus.value) {
case 'authenticated': case 'authenticated':
return 'Estás autenticado. Puedes descargar música.' return 'Estás autenticado. Click para verificar estado.'
case 'unauthenticated': case 'unauthenticated':
return 'No autenticado. Click para iniciar sesión.' return 'Sesión expirada. Click para iniciar sesión de nuevo.'
default: default:
return 'Estado de autenticación desconocido' return 'Verificando estado de autenticación...'
} }
}) })
@@ -127,11 +131,11 @@ const handleClick = () => {
if (isCheckingAuth.value) return if (isCheckingAuth.value) return
if (authStatus.value === 'unauthenticated') { if (authStatus.value === 'unauthenticated') {
// Redirect to trigger Authentik // Forzar reload de la página para que Authentik intercepte
triggerAuth() triggerAuth()
} else if (authStatus.value === 'authenticated') { } else if (authStatus.value === 'authenticated') {
// Re-check auth status // Re-check auth status (forzar, ignorar cache)
checkAuth() checkAuth(true)
} }
} }
</script> </script>

View File

@@ -1,8 +1,8 @@
import { ref, computed, onUnmounted } from 'vue' import { ref, computed } from 'vue'
// Estado global compartido para auth // Estado global compartido para auth
const authChecked = ref(false) const authChecked = ref(true) // Iniciamos como chequeado
const isAuthenticated = ref(false) const isAuthenticated = ref(true) // Asumimos autenticado al inicio (si la página cargó, es porque pasamos Authentik)
const isCheckingAuth = ref(false) const isCheckingAuth = ref(false)
const lastCheckTime = ref(0) const lastCheckTime = ref(0)
@@ -12,10 +12,17 @@ let focusListener: (() => void) | null = null
export const useAuth = () => { export const useAuth = () => {
const checkAuth = async (force = false) => { const checkAuth = async (force = false) => {
// Evitar chequeos duplicados (cache de 10 segundos, reducido) // Si ya sabemos que NO estamos autenticados, no hacer más requests
// (evita loops de CORS con Authentik redirects)
if (!isAuthenticated.value && !force) {
console.log('[Auth] Skipping check - already known to be unauthenticated')
return
}
// Evitar chequeos duplicados (cache de 30 segundos)
const now = Date.now() const now = Date.now()
if (!force && isCheckingAuth.value) return if (!force && isCheckingAuth.value) return
if (!force && authChecked.value && now - lastCheckTime.value < 10000) { if (!force && authChecked.value && now - lastCheckTime.value < 30000) {
return return
} }
@@ -27,6 +34,7 @@ export const useAuth = () => {
method: 'HEAD', // Solo headers, no body method: 'HEAD', // Solo headers, no body
credentials: 'include', // Include cookies for auth credentials: 'include', // Include cookies for auth
cache: 'no-store', // No cachear la respuesta cache: 'no-store', // No cachear la respuesta
redirect: 'error', // No seguir redirects (error si Authentik intenta redirigir)
signal: AbortSignal.timeout(5000) // 5s timeout signal: AbortSignal.timeout(5000) // 5s timeout
}) })
@@ -39,44 +47,35 @@ export const useAuth = () => {
if (wasAuthenticated !== isAuthenticated.value) { if (wasAuthenticated !== isAuthenticated.value) {
console.log('[Auth] Status changed:', isAuthenticated.value ? 'authenticated' : 'unauthenticated') console.log('[Auth] Status changed:', isAuthenticated.value ? 'authenticated' : 'unauthenticated')
} }
} catch (error) { } catch (error: any) {
console.warn('[Auth] Failed to check authentication status:', error) // TypeError: Failed to fetch = probablemente redirect de Authentik (no autenticado)
// En caso de error de red, marcamos como no autenticado // o error de red real
isAuthenticated.value = false console.warn('[Auth] Check failed:', error.message)
authChecked.value = true
// Si el error es por redirect (Authentik intenta redirigir a login), no estamos autenticados
if (error.message && error.message.includes('redirect')) {
const wasAuthenticated = isAuthenticated.value
isAuthenticated.value = false
authChecked.value = true
if (wasAuthenticated) {
console.log('[Auth] Status changed: unauthenticated (redirect detected)')
}
}
// Si no, mantenemos el estado actual (puede ser error de red temporal)
lastCheckTime.value = now lastCheckTime.value = now
} finally { } finally {
isCheckingAuth.value = false isCheckingAuth.value = false
} }
} }
const triggerAuth = async () => { const triggerAuth = () => {
console.log('[Auth] Triggering authentication flow...') console.log('[Auth] Triggering authentication flow - forcing page reload...')
// Primero, hacemos una request al endpoint protegido para forzar // Simplemente recargamos la página completamente
// que Authentik nos redirija a su página de login // Si no estamos autenticados, Authentik interceptará y redirigirá al login
try { // Si ya estamos autenticados, la página se recarga normalmente
const response = await fetch('/api/music', { window.location.reload()
method: 'GET',
credentials: 'include',
redirect: 'manual' // No seguir redirects automáticamente
})
if (!response.ok && (response.status === 401 || response.status === 403)) {
// Si obtenemos 401/403, forzamos un reload completo de la página
// para que Traefik + Authentik intercepten y redirijan al login
console.log('[Auth] Unauthorized - forcing full page reload to trigger auth')
window.location.href = window.location.href
} else if (response.ok) {
// Si la respuesta es OK, ya estamos autenticados
console.log('[Auth] Already authenticated')
await checkAuth(true)
}
} catch (error) {
console.error('[Auth] Error triggering auth:', error)
// En caso de error, forzamos reload de todas formas
window.location.href = window.location.href
}
} }
const markUnauthenticated = () => { const markUnauthenticated = () => {
@@ -92,9 +91,11 @@ export const useAuth = () => {
// (útil si el usuario se autentica en otra pestaña) // (útil si el usuario se autentica en otra pestaña)
if (typeof document !== 'undefined' && !visibilityChangeListener) { if (typeof document !== 'undefined' && !visibilityChangeListener) {
visibilityChangeListener = () => { visibilityChangeListener = () => {
if (!document.hidden) { if (!document.hidden && isAuthenticated.value) {
// Solo chequear si creemos estar autenticados
// (evita spam de requests fallidas)
console.log('[Auth] Tab visible again, checking auth...') console.log('[Auth] Tab visible again, checking auth...')
checkAuth(true) checkAuth(false)
} }
} }
document.addEventListener('visibilitychange', visibilityChangeListener) document.addEventListener('visibilitychange', visibilityChangeListener)
@@ -103,8 +104,11 @@ export const useAuth = () => {
// También chequea cuando la ventana recibe foco // También chequea cuando la ventana recibe foco
if (typeof window !== 'undefined' && !focusListener) { if (typeof window !== 'undefined' && !focusListener) {
focusListener = () => { focusListener = () => {
console.log('[Auth] Window focused, checking auth...') if (isAuthenticated.value) {
checkAuth(true) // Solo chequear si creemos estar autenticados
console.log('[Auth] Window focused, checking auth...')
checkAuth(false)
}
} }
window.addEventListener('focus', focusListener) window.addEventListener('focus', focusListener)
} }