Files
member-platform/frontend/src/pages/AuthCallbackPage.vue

95 lines
2.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="flex items-center justify-center min-h-[70vh]">
<el-card class="w-full max-w-md shadow-md">
<div class="text-center">
<el-icon class="text-3xl text-blue-600 mb-3">
<Loading />
</el-icon>
<h2 class="text-lg font-bold text-gray-800 mb-2">正在登入...</h2>
<p v-if="!error" class="text-sm text-gray-500">
正在驗證身份請稍候
</p>
<p v-if="error" class="text-sm text-red-600 font-medium">
{{ error }}
</p>
</div>
</el-card>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useAuthStore } from '@/stores/auth'
import { exchangeOidcCode } from '@/api/auth'
import { Loading } from '@element-plus/icons-vue'
const router = useRouter()
const route = useRoute()
const authStore = useAuthStore()
const error = ref('')
onMounted(async () => {
try {
const code = route.query.code
const state = route.query.state
const oauthError = route.query.error
const oauthErrorDesc = route.query.error_description
const expectedState = sessionStorage.getItem('oidc_expected_state')
if (oauthError) {
const reason = typeof oauthErrorDesc === 'string' && oauthErrorDesc
? oauthErrorDesc
: String(oauthError)
error.value = `登入失敗:${reason}`
setTimeout(() => router.push('/login'), 3000)
return
}
if (!code) {
error.value = '缺少驗證代碼,登入失敗'
setTimeout(() => router.push('/login'), 2000)
return
}
if (!state || !expectedState || state !== expectedState) {
sessionStorage.removeItem('oidc_expected_state')
error.value = '登入驗證失敗,請重新登入'
setTimeout(() => router.push('/login'), 3000)
return
}
const redirectUri = `${window.location.origin}/auth/callback`
const res = await exchangeOidcCode(code, redirectUri)
const { access_token } = res.data
if (!access_token) {
error.value = '無法取得 access token'
setTimeout(() => router.push('/login'), 2000)
return
}
// 存 token 並取得使用者資料
authStore.setToken(access_token)
await authStore.fetchMe()
// 導向原頁面或預設的 /me
sessionStorage.removeItem('oidc_expected_state')
const redirect = sessionStorage.getItem('post_login_redirect') || '/me'
sessionStorage.removeItem('post_login_redirect')
router.push(redirect)
} catch (err) {
sessionStorage.removeItem('oidc_expected_state')
const detail = err.response?.data?.detail
if (detail === 'invalid_authorization_code') {
error.value = '授權代碼無效,請重新登入'
} else if (detail) {
error.value = `登入失敗:${detail}`
} else {
error.value = '登入過程出錯,請重新登入'
}
setTimeout(() => router.push('/login'), 3000)
}
})
</script>