Skip to content

Commit e221b69

Browse files
committed
Add router-based authentication with route guards
1 parent 39f251a commit e221b69

3 files changed

Lines changed: 59 additions & 17 deletions

File tree

src/App.vue

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@
66
<v-progress-circular indeterminate size="64" />
77
</div>
88

9-
<!-- Authentication Screen -->
10-
<Auth v-else-if="!user" />
11-
12-
<!-- Main App (Authenticated) -->
9+
<!-- Main App -->
1310
<v-container v-else class="pa-0 max-w-md mx-auto" fluid>
14-
<!-- Header -->
15-
<AppHeader :user="user" @logout="handleLogout" @change-password="showPasswordChange = true" />
11+
<!-- Header (only show if user is authenticated) -->
12+
<AppHeader
13+
v-if="user"
14+
:user="user"
15+
@logout="handleLogout"
16+
@change-password="showPasswordChange = true"
17+
/>
1618

1719
<!-- Main Content Area -->
1820
<div class="content-area">
@@ -22,8 +24,8 @@
2224
/>
2325
</div>
2426

25-
<!-- Floating Action Button (only show on home tab) -->
26-
<div v-if="$route.name === 'Home'" class="fixed-fab">
27+
<!-- Floating Action Button (only show on home tab and if authenticated) -->
28+
<div v-if="user && $route.name === 'Home'" class="fixed-fab">
2729
<v-fab
2830
location="bottom center"
2931
size="56"
@@ -33,35 +35,40 @@
3335
/>
3436
</div>
3537

36-
<!-- Bottom Navigation -->
37-
<BottomNavigation />
38+
<!-- Bottom Navigation (only show if authenticated) -->
39+
<BottomNavigation v-if="user" />
3840

39-
<!-- Expense Form Dialog -->
41+
<!-- Expense Form Dialog (only show if authenticated) -->
4042
<ExpenseFormManager
43+
v-if="user"
4144
v-model="showForm"
4245
:expense="editingExpense"
4346
/>
4447

45-
<!-- Password Change Dialog -->
46-
<PasswordChange v-model="showPasswordChange" />
48+
<!-- Password Change Dialog (only show if authenticated) -->
49+
<PasswordChange
50+
v-if="user"
51+
v-model="showPasswordChange"
52+
/>
4753
</v-container>
4854
</v-main>
4955
</v-app>
5056
</template>
5157

5258
<script setup lang="ts">
5359
import { ref, onMounted } from 'vue'
60+
import { useRouter } from 'vue-router'
5461
import { useSupabase } from './composables/useSupabase'
5562
import { useExpenseManagement } from './composables/useExpenseManagement'
5663
import AppHeader from './components/AppHeader.vue'
57-
import Auth from './components/Auth.vue'
5864
import ExpenseFormManager from './components/ExpenseFormManager.vue'
5965
import BottomNavigation from './components/BottomNavigation.vue'
6066
import PasswordChange from './components/PasswordChange.vue'
6167
import { type Expense } from './types'
6268
6369
const { user, loading, signOut, initAuth } = useSupabase()
6470
const { refreshTrigger } = useExpenseManagement()
71+
const router = useRouter()
6572
6673
const showForm = ref(false)
6774
const showPasswordChange = ref(false)
@@ -74,6 +81,7 @@ onMounted(async () => {
7481
7582
const handleLogout = async () => {
7683
await signOut()
84+
router.push('/login')
7785
}
7886
7987
// Handle editing an expense

src/components/Auth.vue

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,10 @@
7979

8080
<script setup lang="ts">
8181
import { ref } from 'vue'
82+
import { useRouter } from 'vue-router'
8283
import { useSupabase } from '@/composables/useSupabase'
8384
85+
const router = useRouter()
8486
const { signIn, signUp } = useSupabase()
8587
8688
const isLogin = ref(true)
@@ -120,7 +122,11 @@ const handleSubmit = async () => {
120122
121123
if (authError) {
122124
error.value = authError.message
123-
} else if (!isLogin.value) {
125+
} else if (isLogin.value) {
126+
// Successful login - redirect to home
127+
router.push('/')
128+
} else {
129+
// Successful signup - show message
124130
successMessage.value = '注册成功!请检查邮箱确认注册。'
125131
}
126132
} catch (err) {

src/router/index.ts

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,32 @@
11
import { createRouter, createWebHistory } from 'vue-router'
2+
import { useSupabase } from '../composables/useSupabase'
23
import HomeView from '../components/HomeView.vue'
34
import ChartsView from '../components/ChartsView.vue'
5+
import Auth from '../components/Auth.vue'
46

57
const routes = [
68
{
79
path: '/',
810
redirect: '/home'
911
},
12+
{
13+
path: '/login',
14+
name: 'Login',
15+
component: Auth
16+
},
1017
{
1118
path: '/home',
1219
name: 'Home',
1320
component: HomeView,
14-
props: true
21+
props: true,
22+
meta: { requiresAuth: true }
1523
},
1624
{
1725
path: '/charts',
1826
name: 'Charts',
1927
component: ChartsView,
20-
props: true
28+
props: true,
29+
meta: { requiresAuth: true }
2130
}
2231
]
2332

@@ -26,4 +35,23 @@ const router = createRouter({
2635
routes
2736
})
2837

38+
// Route guard for authentication
39+
router.beforeEach(async (to, from, next) => {
40+
const { user, initAuth } = useSupabase()
41+
42+
// Initialize auth if not already done
43+
if (user.value === undefined) {
44+
await initAuth()
45+
}
46+
47+
// Check if route requires authentication
48+
if (to.meta.requiresAuth && !user.value) {
49+
next('/login')
50+
} else if (to.path === '/login' && user.value) {
51+
next('/home')
52+
} else {
53+
next()
54+
}
55+
})
56+
2957
export default router

0 commit comments

Comments
 (0)