feat: add CIE authentication callback page with polling mechanism for session verification

This commit is contained in:
gabdevele
2026-06-17 18:03:40 +02:00 Unverified
parent b75e7bbafd
commit 4c42c7963c
5 changed files with 397 additions and 1029 deletions
+119
View File
@@ -0,0 +1,119 @@
<script setup lang="ts">
import { onBeforeUnmount, onMounted, ref } from 'vue'
definePageMeta({
middleware: 'guest'
})
useHead({ title: 'Accesso CIE - Visione' })
const route = useRoute()
const router = useRouter()
const { fetchCieSession, handleLoginSuccess } = useAuth()
const state = computed(() => {
const value = route.query.state
return typeof value === 'string' ? value : ''
})
const isLoading = ref(true)
const errorMessage = ref('')
const statusMessage = ref('Verifica dell’autenticazione CIE in corso...')
let pollTimer: ReturnType<typeof setTimeout> | null = null
let attempts = 0
const maxAttempts = 30
const stopPolling = () => {
if (pollTimer) {
clearTimeout(pollTimer)
pollTimer = null
}
}
const scheduleNextPoll = () => {
pollTimer = setTimeout(checkSession, 2000)
}
const checkSession = async () => {
if (!state.value) {
isLoading.value = false
errorMessage.value = 'Sessione CIE non valida: parametro state mancante.'
return
}
attempts += 1
try {
const res = await fetchCieSession(state.value)
if (res.status === 'authenticated' && res.auth?.token) {
stopPolling()
await handleLoginSuccess(res.auth.token)
return
}
if (['failed', 'expired', 'cancelled', 'error'].includes(res.status)) {
stopPolling()
isLoading.value = false
errorMessage.value = 'Autenticazione CIE non completata. Riprova dal login.'
return
}
if (attempts >= maxAttempts) {
stopPolling()
isLoading.value = false
errorMessage.value = 'Tempo di attesa scaduto durante la verifica CIE. Riprova.'
return
}
statusMessage.value = 'Autenticazione completata sul provider. Attendo conferma finale da Visione...'
scheduleNextPoll()
} catch (err: any) {
stopPolling()
isLoading.value = false
errorMessage.value = err.data?.message || 'Errore durante la verifica della sessione CIE.'
}
}
onMounted(() => {
checkSession()
})
onBeforeUnmount(() => {
stopPolling()
})
</script>
<template>
<div class="d-flex align-items-center bg-light py-5">
<div class="container">
<div class="row justify-content-center">
<div class="col-12 col-md-8 col-lg-6">
<div class="card card-bg shadow-sm">
<div class="card-body p-4 p-md-5 text-center">
<BIIcon name="it-card" size="xl" color="primary" class="mb-3" />
<h1 class="h3 font-weight-bold mb-3">Accesso con CIE</h1>
<div v-if="isLoading" class="py-3">
<div class="spinner-border text-primary mb-3" role="status">
<span class="visually-hidden">Caricamento...</span>
</div>
<p class="text-muted mb-0">{{ statusMessage }}</p>
</div>
<div v-else-if="errorMessage" class="py-2">
<div class="alert alert-danger text-start mb-4" role="alert">
{{ errorMessage }}
</div>
<button class="btn btn-primary" @click="router.push('/auth/login')">
Torna al login
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
+27 -3
View File
@@ -7,16 +7,20 @@ definePageMeta({
useHead({ title: 'Accedi - Visione' })
const { requestOtp, verifyOtp, handleLoginSuccess } = useAuth()
const runtimeConfig = useRuntimeConfig()
const { requestOtp, verifyOtp, handleLoginSuccess, startCieLogin } = useAuth()
// UI State
const otpStep = ref<1 | 2>(1)
const isLoading = ref(false)
const isCieLoading = ref(false)
const errorMessage = ref('')
const email = ref('')
const otpCode = ref('')
const cieCallbackUrl = `${runtimeConfig.public.url}/auth/cie/callback`
const handleRequestOtp = async () => {
isLoading.value = true
errorMessage.value = ''
@@ -42,6 +46,21 @@ const handleVerifyOtp = async () => {
isLoading.value = false
}
}
const handleCieLogin = async () => {
isCieLoading.value = true
errorMessage.value = ''
try {
const res = await startCieLogin(cieCallbackUrl)
await navigateTo(res.authorization_url, {
external: true,
replace: true,
})
} catch (err: any) {
errorMessage.value = err.data?.message || 'Avvio autenticazione CIE non riuscito. Riprova.'
isCieLoading.value = false
}
}
</script>
<template>
@@ -61,9 +80,14 @@ const handleVerifyOtp = async () => {
<div class="card-body p-4 p-md-5">
<button class="btn btn-primary w-100 mb-4 d-flex align-items-center justify-content-center gap-2" disabled title="Integrazione CIE prevista per la fase successiva">
<button
class="btn btn-primary w-100 mb-4 d-flex align-items-center justify-content-center gap-2"
:disabled="isCieLoading || isLoading"
@click="handleCieLogin"
>
<span v-if="isCieLoading" class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
<BIIcon name="it-card" size="sm" color="white" />
Entra con CIE (Presto disponibile)
Entra con CIE
</button>
<div class="d-flex align-items-center my-4">