fix: auth flow - logout nuclear, router redirige admin a panel, login sin bloqueo BD

This commit is contained in:
2026-02-25 22:38:03 -05:00
parent 84055a25de
commit 963d255ea2
4 changed files with 69 additions and 28 deletions

View File

@ -146,9 +146,8 @@ const openReportModal = () => {
} }
const handleLogout = () => { const handleLogout = () => {
authStore.logout()
showMenu.value = false showMenu.value = false
router.push('/login') authStore.logout()
} }
</script> </script>

View File

@ -17,16 +17,18 @@ const authStore = useAuthStore()
const handleLogin = async () => { const handleLogin = async () => {
isLoading.value = true isLoading.value = true
errorMessage.value = '' errorMessage.value = ''
console.log('Iniciando Login con correo...')
try { try {
await authStore.login(email.value.trim().toLowerCase(), password.value) await authStore.login(email.value.trim().toLowerCase(), password.value)
// Esperar a que el perfil se cargue globalmente para saber a qué pantalla navegar // Esperar hasta que el perfil esté cargado (máx 3 segundos)
setTimeout(() => { let attempts = 0
const r = authStore.role || 'PASSENGER' while (!authStore.role && attempts < 30) {
navigateByUserRole(r) await new Promise(res => setTimeout(res, 100))
}, 800) attempts++
}
navigateByUserRole(authStore.role || 'PASSENGER')
} catch (error: any) { } catch (error: any) {
console.error('Error Login detallado:', error) console.error('Error Login detallado:', error)

View File

@ -147,12 +147,13 @@ const router = createRouter({
}) })
router.beforeEach(async (to, _from, next) => { router.beforeEach(async (to, _from, next) => {
// Rutas públicas: siempre pasan sin verificación // Rutas completamente públicas (splash, login)
if (!to.meta.requiresAuth && !to.meta.role) { const publicRoutes = ['/login', '/splash', '/']
if (publicRoutes.includes(to.path)) {
return next() return next()
} }
// Leer sesión activa de Supabase (sustituye el viejo localStorage) // Leer sesión activa de Supabase
const { data: { session } } = await supabase.auth.getSession() const { data: { session } } = await supabase.auth.getSession()
// Ruta protegida sin sesión → redirige a login // Ruta protegida sin sesión → redirige a login
@ -160,8 +161,8 @@ router.beforeEach(async (to, _from, next) => {
return next('/login') return next('/login')
} }
// Ruta con restricción de rol → verificar en la BD // Si hay sesión, obtener el rol real del usuario
if (to.meta.role && session) { if (session) {
const { data: profile } = await supabase const { data: profile } = await supabase
.from('users') .from('users')
.select('role') .select('role')
@ -169,18 +170,27 @@ router.beforeEach(async (to, _from, next) => {
.single() .single()
const userRole = profile?.role?.toUpperCase() || 'PASSENGER' const userRole = profile?.role?.toUpperCase() || 'PASSENGER'
// Si el admin entra a rutas de pasajero → redirigir al panel admin
const passengerRoutes = ['/map', '/schedule', '/discover', '/transport', '/favorites', '/profile', '/coupons']
if (userRole === 'ADMIN' && passengerRoutes.some(r => to.path.startsWith(r))) {
return next('/admin')
}
// Ruta con restricción de rol → verificar permiso
if (to.meta.role) {
const allowedRoles = Array.isArray(to.meta.role) const allowedRoles = Array.isArray(to.meta.role)
? (to.meta.role as string[]).map(r => r.toUpperCase()) ? (to.meta.role as string[]).map(r => r.toUpperCase())
: [(to.meta.role as string).toUpperCase()] : [(to.meta.role as string).toUpperCase()]
if (!allowedRoles.includes(userRole)) { if (!allowedRoles.includes(userRole)) {
// Redirigir a la vista correcta según su rol real
if (userRole === 'ADMIN') return next('/admin') if (userRole === 'ADMIN') return next('/admin')
else if (userRole === 'DRIVER') return next('/driver') else if (userRole === 'DRIVER') return next('/driver')
else if (userRole === 'PROMOTER') return next('/promoter') else if (userRole === 'PROMOTER') return next('/promoter')
else return next('/map') else return next('/map')
} }
} }
}
next() next()
}) })

View File

@ -36,16 +36,46 @@ export const useAuthStore = defineStore('auth', () => {
}) })
async function login(email: string, pass: string) { async function login(email: string, pass: string) {
// Use standard Supabase signIn const { data, error } = await supabase.auth.signInWithPassword({ email, password: pass })
const { error } = await supabase.auth.signInWithPassword({ email, password: pass })
if (error) throw new Error(error.message) if (error) throw new Error(error.message)
if (data.user) {
// Establecer sesión y rol inmediatamente desde el JWT (sin esperar BD)
userSession.value = data.session
// Usar user_metadata como perfil temporal para que el rol esté listo al instante
userProfile.value = {
id: data.user.id,
email: data.user.email,
full_name: data.user.user_metadata?.full_name || data.user.email,
role: data.user.user_metadata?.role || 'PASSENGER'
}
// Cargar perfil completo de BD en background (sin bloquear navegación)
supabase.from('users').select('*').eq('id', data.user.id).single()
.then(({ data: profile }) => { if (profile) userProfile.value = profile })
.catch(() => { })
}
} }
async function logout() { function logout() {
await supabase.auth.signOut() // Limpiar estado de Pinia inmediatamente
userSession.value = null userSession.value = null
userProfile.value = null userProfile.value = null
window.location.href = '/'
// Limpiar TODA la sesión del navegador sin esperar a Supabase
localStorage.clear()
sessionStorage.clear()
// Limpiar IndexedDB donde Supabase guarda tokens
try {
indexedDB.deleteDatabase('supabase-js-auth')
indexedDB.deleteDatabase('supabase')
} catch (_) { }
// Llamar signOut en background (sin await - no bloqueamos)
supabase.auth.signOut().catch(() => { })
// Redirigir forzando recarga completa del navegador
window.location.replace('/login')
} }
return { return {