vamos
All checks were successful
build-and-deploy / build (push) Successful in 23s
build-and-deploy / deploy (push) Successful in 3s

This commit is contained in:
2025-10-12 00:59:50 -06:00
parent 1f087eb6f3
commit 98fb972a4e
4 changed files with 173 additions and 34 deletions

View File

@@ -1,4 +1,4 @@
import { ref, computed } from 'vue'
import { ref, computed, onUnmounted } from 'vue'
// Estado global compartido para auth
const authChecked = ref(false)
@@ -6,12 +6,16 @@ const isAuthenticated = ref(false)
const isCheckingAuth = ref(false)
const lastCheckTime = ref(0)
// Listener para cambios de autenticación desde otras tabs/ventanas
let visibilityChangeListener: (() => void) | null = null
let focusListener: (() => void) | null = null
export const useAuth = () => {
const checkAuth = async (force = false) => {
// Evitar chequeos duplicados (cache de 30 segundos)
// Evitar chequeos duplicados (cache de 10 segundos, reducido)
const now = Date.now()
if (!force && isCheckingAuth.value) return
if (!force && authChecked.value && now - lastCheckTime.value < 30000) {
if (!force && authChecked.value && now - lastCheckTime.value < 10000) {
return
}
@@ -22,23 +26,23 @@ export const useAuth = () => {
const response = await fetch('/api/music', {
method: 'HEAD', // Solo headers, no body
credentials: 'include', // Include cookies for auth
cache: 'no-store', // No cachear la respuesta
signal: AbortSignal.timeout(5000) // 5s timeout
})
// Si responde 200, estamos autenticados
// Si responde 401/403, no estamos autenticados
const wasAuthenticated = isAuthenticated.value
isAuthenticated.value = response.ok
authChecked.value = true
lastCheckTime.value = now
console.log('[Auth] Status:', isAuthenticated.value ? 'authenticated' : 'unauthenticated')
// Log cambios de estado
if (wasAuthenticated !== isAuthenticated.value) {
console.log('[Auth] Status changed:', isAuthenticated.value ? 'authenticated' : 'unauthenticated')
}
} catch (error) {
console.warn('[Auth] Failed to check authentication status:', error)
// En caso de error de red, mantenemos el último estado conocido si existe
// Solo marcamos como no autenticado si es el primer chequeo
if (!authChecked.value) {
isAuthenticated.value = false
}
// En caso de error de red, marcamos como no autenticado
isAuthenticated.value = false
authChecked.value = true
lastCheckTime.value = now
} finally {
@@ -46,24 +50,77 @@ export const useAuth = () => {
}
}
const triggerAuth = () => {
console.log('[Auth] Redirecting to trigger Authentik...')
// Redirige a la página principal para que Authentik intercepte
// Si ya estamos en /, forzamos reload
if (window.location.pathname === '/') {
window.location.reload()
} else {
window.location.href = '/'
const triggerAuth = async () => {
console.log('[Auth] Triggering authentication flow...')
// Primero, hacemos una request al endpoint protegido para forzar
// que Authentik nos redirija a su página de login
try {
const response = await fetch('/api/music', {
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 = () => {
// Helper para marcar como no autenticado (útil cuando detectamos 401/403)
console.log('[Auth] Marking as unauthenticated')
isAuthenticated.value = false
authChecked.value = true
lastCheckTime.value = Date.now()
}
const setupVisibilityListener = () => {
// Re-chequea auth cuando la pestaña vuelve a ser visible
// (útil si el usuario se autentica en otra pestaña)
if (typeof document !== 'undefined' && !visibilityChangeListener) {
visibilityChangeListener = () => {
if (!document.hidden) {
console.log('[Auth] Tab visible again, checking auth...')
checkAuth(true)
}
}
document.addEventListener('visibilitychange', visibilityChangeListener)
}
// También chequea cuando la ventana recibe foco
if (typeof window !== 'undefined' && !focusListener) {
focusListener = () => {
console.log('[Auth] Window focused, checking auth...')
checkAuth(true)
}
window.addEventListener('focus', focusListener)
}
}
const cleanupListeners = () => {
if (visibilityChangeListener) {
document.removeEventListener('visibilitychange', visibilityChangeListener)
visibilityChangeListener = null
}
if (focusListener) {
window.removeEventListener('focus', focusListener)
focusListener = null
}
}
const authStatus = computed(() => {
if (!authChecked.value) return 'unknown'
return isAuthenticated.value ? 'authenticated' : 'unauthenticated'
@@ -76,6 +133,8 @@ export const useAuth = () => {
authStatus,
checkAuth,
triggerAuth,
markUnauthenticated
markUnauthenticated,
setupVisibilityListener,
cleanupListeners
}
}