Files
member-frontend/src/pages/LoginPage.vue

123 lines
3.1 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">
<template #header>
<div class="text-center">
<h1 class="text-xl font-bold text-gray-800">member.ose.tw</h1>
<p class="text-sm text-gray-500 mt-1">可使用帳號登入或 Google SSO 登入</p>
</div>
</template>
<el-alert
v-if="error"
:title="error"
type="error"
show-icon
:closable="false"
class="mb-4"
/>
<el-form @submit.prevent="handlePasswordLogin" label-position="top">
<el-form-item label="帳號">
<el-input
v-model="form.username"
placeholder="username 或 email"
autocomplete="username"
@keyup.enter="handlePasswordLogin"
/>
</el-form-item>
<el-button
type="primary"
class="w-full"
:loading="passwordLoading"
@click="handlePasswordLogin"
>
使用帳號登入
</el-button>
</el-form>
<el-divider></el-divider>
<el-button
type="success"
class="w-full"
:loading="oidcLoading"
@click="handleOidcLogin"
>
使用 Google SSO 登入
</el-button>
<div class="mt-4 text-xs text-gray-400 text-center space-y-1">
<p>登入會跳轉到 Authentik 驗證完成後自動返回</p>
<p>登入成功後 access token 會存於本機 localStorage</p>
</div>
</el-card>
</div>
</template>
<script setup>
import { reactive, ref } from 'vue'
import { useRoute } from 'vue-router'
import { getOidcAuthorizeUrl } from '@/api/auth'
const route = useRoute()
const passwordLoading = ref(false)
const oidcLoading = ref(false)
const error = ref('')
const form = reactive({
username: ''
})
function getPostLoginRedirect() {
const redirect = route.query.redirect || '/me'
return typeof redirect === 'string' ? redirect : '/me'
}
async function handlePasswordLogin() {
if (!form.username) {
error.value = '請輸入帳號'
return
}
passwordLoading.value = true
error.value = ''
try {
await redirectToOidc({
loginHint: form.username,
prompt: 'login'
})
} catch (_err) {
error.value = '登入失敗,請稍後再試'
} finally {
passwordLoading.value = false
}
}
async function handleOidcLogin() {
oidcLoading.value = true
error.value = ''
try {
await redirectToOidc({
prompt: 'select_account'
})
} catch (err) {
error.value = err.message || '登入失敗,請稍後再試'
} finally {
oidcLoading.value = false
}
}
async function redirectToOidc(options = {}) {
sessionStorage.setItem('post_login_redirect', getPostLoginRedirect())
const callbackUrl = `${window.location.origin}/auth/callback`
const res = await getOidcAuthorizeUrl(callbackUrl, options)
const authorizeUrl = res.data.authorize_url
const parsed = new URL(authorizeUrl)
const state = parsed.searchParams.get('state')
if (state) {
sessionStorage.setItem('oidc_expected_state', state)
}
window.location.href = authorizeUrl
}
</script>