feat: add username-password login flow via authentik token endpoint
This commit is contained in:
4
src/api/auth.js
Normal file
4
src/api/auth.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import { userHttp } from './http'
|
||||||
|
|
||||||
|
export const loginWithPassword = (username, password) =>
|
||||||
|
userHttp.post('/auth/login', { username, password })
|
||||||
@@ -4,21 +4,27 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<h1 class="text-xl font-bold text-gray-800">member.ose.tw</h1>
|
<h1 class="text-xl font-bold text-gray-800">member.ose.tw</h1>
|
||||||
<p class="text-sm text-gray-500 mt-1">請輸入 Authentik Access Token 登入</p>
|
<p class="text-sm text-gray-500 mt-1">使用 Authentik 帳號密碼登入</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-form @submit.prevent="handleLogin">
|
<el-form @submit.prevent="handleLogin">
|
||||||
<el-form-item>
|
<el-form-item label="帳號">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="token"
|
v-model="username"
|
||||||
type="textarea"
|
placeholder="請輸入 Authentik username / email"
|
||||||
:rows="4"
|
|
||||||
placeholder="貼上 Bearer Token..."
|
|
||||||
resize="none"
|
|
||||||
clearable
|
clearable
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item label="密碼">
|
||||||
|
<el-input
|
||||||
|
v-model="password"
|
||||||
|
type="password"
|
||||||
|
placeholder="請輸入密碼"
|
||||||
|
clearable
|
||||||
|
show-password
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
<el-alert
|
<el-alert
|
||||||
v-if="error"
|
v-if="error"
|
||||||
@@ -35,16 +41,14 @@
|
|||||||
native-type="submit"
|
native-type="submit"
|
||||||
class="w-full"
|
class="w-full"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
:disabled="!token.trim()"
|
:disabled="!username.trim() || !password.trim()"
|
||||||
>
|
>
|
||||||
登入
|
登入
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
<p class="text-xs text-gray-400 text-center mt-2">
|
<p class="text-xs text-gray-400 text-center mt-2">登入成功後 access token 會存於本機 localStorage</p>
|
||||||
Token 從 Authentik 取得,存於本機 localStorage
|
|
||||||
</p>
|
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -53,29 +57,34 @@
|
|||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { useRouter, useRoute } from 'vue-router'
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
import { useAuthStore } from '@/stores/auth'
|
import { useAuthStore } from '@/stores/auth'
|
||||||
|
import { loginWithPassword } from '@/api/auth'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const authStore = useAuthStore()
|
const authStore = useAuthStore()
|
||||||
|
|
||||||
const token = ref('')
|
const username = ref('')
|
||||||
|
const password = ref('')
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const error = ref('')
|
const error = ref('')
|
||||||
|
|
||||||
async function handleLogin() {
|
async function handleLogin() {
|
||||||
if (!token.value.trim()) return
|
if (!username.value.trim() || !password.value.trim()) return
|
||||||
loading.value = true
|
loading.value = true
|
||||||
error.value = ''
|
error.value = ''
|
||||||
try {
|
try {
|
||||||
authStore.setToken(token.value.trim())
|
const loginRes = await loginWithPassword(username.value.trim(), password.value)
|
||||||
|
authStore.setToken(loginRes.data.access_token)
|
||||||
await authStore.fetchMe()
|
await authStore.fetchMe()
|
||||||
const redirect = route.query.redirect || '/me'
|
const redirect = route.query.redirect || '/me'
|
||||||
router.push(redirect)
|
router.push(redirect)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
authStore.logout()
|
authStore.logout()
|
||||||
const detail = err.response?.data?.detail
|
const detail = err.response?.data?.detail
|
||||||
if (detail === 'missing_bearer_token' || detail === 'invalid_bearer_token') {
|
if (detail === 'invalid_username_or_password') {
|
||||||
error.value = 'Token 無效或已過期,請重新取得'
|
error.value = '帳號或密碼錯誤'
|
||||||
|
} else if (detail === 'authentik_login_not_configured') {
|
||||||
|
error.value = '後端尚未設定 Authentik 登入參數'
|
||||||
} else {
|
} else {
|
||||||
error.value = '登入失敗,請稍後再試'
|
error.value = '登入失敗,請稍後再試'
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user