Wat is het probleem?
Sommige pagina's mogen alleen zichtbaar zijn voor ingelogde gebruikers — bijvoorbeeld /dashboard of /profile. Als een uitgelogde gebruiker daar naartoe gaat, wil je hem terugsturen naar de login.
Vue Router heeft hiervoor navigation guards: code die draait voordat de gebruiker naar een nieuwe pagina gaat.
Vooraf: deze pagina gebruikt de Auth Store en Vue Router. Zorg dat die staan.
Frontend beveiliging is niet écht veilig. Een slimme gebruiker kan je JS aanpassen. De échte beveiliging zit altijd op de server (API checkt het token). Navigation guards zijn voor de gebruikerservaring — niet de echte security.
Routes markeren als beveiligd
In je route-config voeg je meta: { requiresAuth: true } toe aan de routes die alleen voor ingelogde users zijn:
// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
import LoginView from '../views/LoginView.vue'
import DashboardView from '../views/DashboardView.vue'
import ProfileView from '../views/ProfileView.vue'
const router = createRouter({
history: createWebHistory(),
routes: [
{ path: '/', component: HomeView },
{ path: '/login', component: LoginView },
// Beveiligd
{
path: '/dashboard',
component: DashboardView,
meta: { requiresAuth: true }
},
{
path: '/profile',
component: ProfileView,
meta: { requiresAuth: true }
}
]
})
export default router
Waarom met meta? Zo houd je de check op één plek (de guard) en hoef je per route alleen aan te geven of hij beveiligd is. Veel cleaner dan een lijst hard-coden.
De Navigation Guard
Voeg vlak voor export default router een beforeEach toe. Die draait voor elke navigatie:
// src/router/index.js
import { useAuthStore } from '@/stores/auth'
// ...routes...
router.beforeEach((to) => {
const auth = useAuthStore()
// Heeft deze route auth nodig EN is user niet ingelogd?
if (to.meta.requiresAuth && !auth.isLoggedIn) {
return '/login' // → omleiden naar login
}
// Anders: gewoon doorlaten
})
export default router
Hoe werkt beforeEach?
- Draait voor elke navigatie in je app
to= de route waar de gebruiker naartoe gaat- Return een pad-string → omleiden naar die route
- Return niks of
true→ gewoon doorlaten - Return
false→ blokkeer de navigatie
Compleet voorbeeld
Alles bij elkaar in src/router/index.js:
// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import { useAuthStore } from '@/stores/auth'
import HomeView from '../views/HomeView.vue'
import LoginView from '../views/LoginView.vue'
import RegisterView from '../views/RegisterView.vue'
import DashboardView from '../views/DashboardView.vue'
import ProfileView from '../views/ProfileView.vue'
const router = createRouter({
history: createWebHistory(),
routes: [
{ path: '/', component: HomeView },
{ path: '/login', component: LoginView },
{ path: '/register', component: RegisterView },
{
path: '/dashboard',
component: DashboardView,
meta: { requiresAuth: true }
},
{
path: '/profile',
component: ProfileView,
meta: { requiresAuth: true }
}
]
})
router.beforeEach((to) => {
const auth = useAuthStore()
if (to.meta.requiresAuth && !auth.isLoggedIn) {
return '/login'
}
})
export default router
Bonus: redirect terug na login
Wil je dat na inloggen de gebruiker terugkomt op de pagina die hij wilde zien? Sla het oorspronkelijke pad op als query string:
router.beforeEach((to) => {
const auth = useAuthStore()
if (to.meta.requiresAuth && !auth.isLoggedIn) {
return {
path: '/login',
query: { redirect: to.fullPath }
}
}
})
Lees in LoginView.vue de query en stuur na succes terug:
// LoginView.vue
const router = useRouter()
const route = useRoute()
const handleLogin = () => {
auth.login({ ... })
// Terug naar oorspronkelijke pagina, of dashboard als default
const redirect = route.query.redirect || '/dashboard'
router.push(redirect)
}
Wat heb je nu? Bezoek /profile uitgelogd → kom op /login?redirect=/profile. Na inloggen ga je direct naar /profile. Veel betere ervaring dan altijd op het dashboard belanden.
Belangrijke Regels
meta: { requiresAuth: true }op routes die beveiligd zijnrouter.beforeEachdoet de check — één keer, op één plek- Auth store binnen de guard aanroepen, niet erbuiten (Pinia moet eerst geladen zijn)
- Login-pagina mag NIET
requiresAuthhebben — anders kun je niet inloggen! - Echte security zit op je server — guards zijn UX, niet beveiliging
Veelgemaakte Fouten
Fout — auth store buiten guard aanroepen:
// src/router/index.js
const auth = useAuthStore() // ❌ Pinia is hier nog niet ready
router.beforeEach((to) => {
if (to.meta.requiresAuth && !auth.isLoggedIn) { ... }
})
Goed — binnen de guard:
router.beforeEach((to) => {
const auth = useAuthStore() // ✅ binnen de guard
if (to.meta.requiresAuth && !auth.isLoggedIn) { ... }
})
Fout — login pagina als beveiligd markeren:
{
path: '/login',
component: LoginView,
meta: { requiresAuth: true } // ❌ infinite redirect!
}
De guard stuurt je naar /login → /login is beveiligd → stuurt je weer naar /login → ...
Goed — login is altijd vrij toegankelijk:
{ path: '/login', component: LoginView } // ✅
Fout — niks teruggeven bij geslaagde auth:
router.beforeEach((to) => {
const auth = useAuthStore()
if (to.meta.requiresAuth && !auth.isLoggedIn) {
return '/login'
}
return false // ❌ alle andere navigaties geblokkeerd!
})
Goed — niks teruggeven = doorlaten:
router.beforeEach((to) => {
const auth = useAuthStore()
if (to.meta.requiresAuth && !auth.isLoggedIn) {
return '/login'
}
// ✅ implicit: niks return = doorlaten
})