83 lines
3.1 KiB
TypeScript
83 lines
3.1 KiB
TypeScript
import { useAuthStore } from '~/stores/auth'
|
|
|
|
export default defineNuxtRouteMiddleware((to, from) => {
|
|
// Skip auth checks on server-side (SSR) - localStorage not available
|
|
if (process.server) {
|
|
return
|
|
}
|
|
|
|
const authStore = useAuthStore()
|
|
const nuxtApp = useNuxtApp()
|
|
|
|
// Public routes that don't require authentication
|
|
const publicRoutes = ['/login', '/forgot-password', '/reset-password']
|
|
|
|
// Check if route requires authentication
|
|
const requiresAuth = !publicRoutes.includes(to.path)
|
|
|
|
// If route requires auth and user is not authenticated, redirect to login
|
|
if (requiresAuth && !authStore.isAuthenticated) {
|
|
return navigateTo('/login')
|
|
}
|
|
|
|
// If user is authenticated and trying to access login page, redirect to dashboard
|
|
if (to.path === '/login' && authStore.isAuthenticated) {
|
|
return navigateTo('/dashboard')
|
|
}
|
|
|
|
// Check role-based access for protected routes
|
|
if (requiresAuth && authStore.isAuthenticated) {
|
|
const routeMeta = to.meta || {}
|
|
const requiredRole = routeMeta.requiredRole as string | undefined
|
|
const minRank = routeMeta.minRank as number | undefined
|
|
const requiredPermission = routeMeta.requiredPermission as string | undefined
|
|
|
|
// Check role requirement
|
|
if (requiredRole && authStore.getUserRole !== requiredRole) {
|
|
console.warn(`Access denied: Route requires role ${requiredRole}, user has ${authStore.getUserRole}`)
|
|
return navigateTo('/unauthorized')
|
|
}
|
|
|
|
// Check rank requirement
|
|
if (minRank !== undefined && !authStore.hasRank(minRank)) {
|
|
console.warn(`Access denied: Route requires rank ${minRank}, user has rank ${authStore.getUserRank}`)
|
|
return navigateTo('/unauthorized')
|
|
}
|
|
|
|
// Check permission requirement
|
|
if (requiredPermission && !authStore.hasPermission(requiredPermission)) {
|
|
console.warn(`Access denied: Route requires permission ${requiredPermission}`)
|
|
return navigateTo('/unauthorized')
|
|
}
|
|
|
|
// Check geographical scope for scoped routes
|
|
const requiredScopeId = routeMeta.requiredScopeId as number | undefined
|
|
const requiredRegionCode = routeMeta.requiredRegionCode as string | undefined
|
|
|
|
if (requiredScopeId || requiredRegionCode) {
|
|
if (!authStore.canAccessScope(requiredScopeId || 0, requiredRegionCode)) {
|
|
console.warn(`Access denied: User cannot access requested scope`)
|
|
return navigateTo('/unauthorized')
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add auth headers to all API requests if authenticated
|
|
if (process.client && authStore.isAuthenticated && authStore.token) {
|
|
const { $api } = nuxtApp
|
|
if ($api && $api.defaults) {
|
|
$api.defaults.headers.common['Authorization'] = `Bearer ${authStore.token}`
|
|
|
|
// Add geographical scope headers for backend filtering
|
|
if (authStore.getScopeId) {
|
|
$api.defaults.headers.common['X-Scope-Id'] = authStore.getScopeId.toString()
|
|
}
|
|
if (authStore.getRegionCode) {
|
|
$api.defaults.headers.common['X-Region-Code'] = authStore.getRegionCode
|
|
}
|
|
if (authStore.getScopeLevel) {
|
|
$api.defaults.headers.common['X-Scope-Level'] = authStore.getScopeLevel
|
|
}
|
|
}
|
|
}
|
|
}) |