feat: implement authentication flow with OAuth login page
This commit is contained in:
parent
10b2056954
commit
77538a7dfd
5 changed files with 146 additions and 10 deletions
|
@ -1,9 +1,21 @@
|
|||
<template>
|
||||
<v-app>
|
||||
<router-view />
|
||||
<v-main>
|
||||
<router-view />
|
||||
</v-main>
|
||||
</v-app>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
//
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { onMounted } from 'vue';
|
||||
|
||||
const authStore = useAuthStore();
|
||||
|
||||
onMounted(async () => {
|
||||
// If user has a token, fetch user info
|
||||
if (authStore.isAuthenticated) {
|
||||
await authStore.fetchUserInfo();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
39
web/src/pages/auth.vue
Normal file
39
web/src/pages/auth.vue
Normal file
|
@ -0,0 +1,39 @@
|
|||
<template>
|
||||
<v-container class="fill-height">
|
||||
<v-responsive class="align-center fill-height mx-auto" max-width="500">
|
||||
<v-card class="pa-6" elevation="8">
|
||||
<div class="text-center mb-6">
|
||||
<v-img
|
||||
class="mx-auto mb-6"
|
||||
height="100"
|
||||
src="@/assets/logo.png"
|
||||
width="100"
|
||||
/>
|
||||
<h1 class="text-h4 font-weight-bold mb-2">Welcome</h1>
|
||||
<p class="text-body-1">Please sign in to continue</p>
|
||||
</div>
|
||||
|
||||
<v-divider class="mb-6"></v-divider>
|
||||
|
||||
<v-btn
|
||||
block
|
||||
color="primary"
|
||||
size="large"
|
||||
@click="login"
|
||||
prepend-icon="mdi-login"
|
||||
>
|
||||
Sign in with OAuth
|
||||
</v-btn>
|
||||
</v-card>
|
||||
</v-responsive>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
const router = useRouter();
|
||||
|
||||
function login() {
|
||||
// Redirect to the OAuth login endpoint
|
||||
window.location.href = '/oauth/login';
|
||||
}
|
||||
</script>
|
|
@ -14,6 +14,22 @@ const router = createRouter({
|
|||
routes: setupLayouts(routes),
|
||||
})
|
||||
|
||||
// Add authentication guard
|
||||
router.beforeEach((to, from, next) => {
|
||||
// Check if the user is authenticated
|
||||
const isAuthenticated = !!localStorage.getItem('auth_token');
|
||||
|
||||
// If route requires auth and user is not authenticated, redirect to auth page
|
||||
if (to.path !== '/auth' && !isAuthenticated) {
|
||||
next('/auth');
|
||||
} else if (to.path === '/auth' && isAuthenticated) {
|
||||
// If user is already authenticated and tries to access auth page, redirect to home
|
||||
next('/');
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
// Workaround for https://github.com/vitejs/vite/issues/11804
|
||||
router.onError((err, to) => {
|
||||
if (err?.message?.includes?.('Failed to fetch dynamically imported module')) {
|
||||
|
|
53
web/src/stores/auth.ts
Normal file
53
web/src/stores/auth.ts
Normal file
|
@ -0,0 +1,53 @@
|
|||
// Auth store to manage authentication state
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
export const useAuthStore = defineStore('auth', {
|
||||
state: () => ({
|
||||
token: localStorage.getItem('auth_token') || null,
|
||||
user: null as any | null,
|
||||
}),
|
||||
|
||||
getters: {
|
||||
isAuthenticated: (state) => !!state.token,
|
||||
},
|
||||
|
||||
actions: {
|
||||
setToken(token: string) {
|
||||
this.token = token;
|
||||
localStorage.setItem('auth_token', token);
|
||||
},
|
||||
|
||||
setUser(user: any) {
|
||||
this.user = user;
|
||||
},
|
||||
|
||||
logout() {
|
||||
this.token = null;
|
||||
this.user = null;
|
||||
localStorage.removeItem('auth_token');
|
||||
},
|
||||
|
||||
async fetchUserInfo() {
|
||||
if (!this.token) return;
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/v1/health', {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${this.token}`
|
||||
}
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
this.setUser(data.user);
|
||||
} else {
|
||||
// If token is invalid, logout
|
||||
this.logout();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch user info:', error);
|
||||
this.logout();
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
Loading…
Add table
Add a link
Reference in a new issue