feat: add role negation and negate some routes to admins
This commit is contained in:
@@ -26,15 +26,15 @@ onUnmounted(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const { isAuthenticated, user, logout } = useAuth()
|
||||||
|
const panelLabel = computed(() => isAdmin(user.value?.role) ? 'Pannello' : 'Dashboard')
|
||||||
|
|
||||||
const navLinks = [
|
const navLinks = [
|
||||||
{ name: 'Home', path: '/' },
|
{ name: 'Home', path: '/' },
|
||||||
{ name: 'Fai una segnalazione', path: '/reports/new' },
|
...(isCitizen(user.value?.role) ? [{ name: 'Fai una segnalazione', path: '/reports/new' }] : []),
|
||||||
{ name: 'Esplora i dati', path: '/open-data' },
|
{ name: 'Esplora i dati', path: '/open-data' },
|
||||||
{ name: 'Come funziona', path: '/info' }
|
{ name: 'Come funziona', path: '/info' }
|
||||||
]
|
]
|
||||||
|
|
||||||
const { isAuthenticated, user, logout } = useAuth()
|
|
||||||
const panelLabel = computed(() => isAdmin(user.value?.role) ? 'Pannello' : 'Dashboard')
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { checkRoleAccess, type MetaRoleRequirement } from '~/utils/roles'
|
||||||
|
|
||||||
export default defineNuxtRouteMiddleware(async (to) => {
|
export default defineNuxtRouteMiddleware(async (to) => {
|
||||||
const auth = useAuth()
|
const auth = useAuth()
|
||||||
|
|
||||||
@@ -14,13 +16,13 @@ export default defineNuxtRouteMiddleware(async (to) => {
|
|||||||
return navigateTo('/auth/login')
|
return navigateTo('/auth/login')
|
||||||
}
|
}
|
||||||
|
|
||||||
const requiredRole = to.meta.auth?.role
|
const requiredRole = to.meta.auth?.role as MetaRoleRequirement | undefined
|
||||||
|
|
||||||
if (requiredRole && auth.user.value) {
|
if (requiredRole && auth.user.value) {
|
||||||
const userRole = auth.user.value.role
|
const userRole = auth.user.value.role
|
||||||
|
|
||||||
if (!hasMinimumRole(userRole, requiredRole)) {
|
if (!checkRoleAccess(userRole, requiredRole)) {
|
||||||
console.warn(`[Auth] User role ${userRole} insufficient for required ${requiredRole}`)
|
console.warn(`[Auth] User role '${userRole}' rejected for route requirement:`, requiredRole)
|
||||||
return navigateTo('/')
|
return navigateTo('/')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ import type { CreateReportRequest } from '~/types/api'
|
|||||||
|
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
middleware: 'auth',
|
middleware: 'auth',
|
||||||
|
auth: {
|
||||||
|
role: ['!ADMIN', '!OPERATOR']
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
useHead({ title: 'Nuova segnalazione - Visione' })
|
useHead({ title: 'Nuova segnalazione - Visione' })
|
||||||
|
|||||||
+33
-2
@@ -5,6 +5,8 @@ export const ROLES = {
|
|||||||
} as const
|
} as const
|
||||||
|
|
||||||
export type Role = keyof typeof ROLES
|
export type Role = keyof typeof ROLES
|
||||||
|
export type NegatedRole = `!${Role}`
|
||||||
|
export type MetaRoleRequirement = Role | NegatedRole | Array<Role | NegatedRole>
|
||||||
|
|
||||||
export const ROLE_LEVELS: Record<string, number> = {
|
export const ROLE_LEVELS: Record<string, number> = {
|
||||||
[ROLES.CITIZEN]: 1,
|
[ROLES.CITIZEN]: 1,
|
||||||
@@ -17,12 +19,12 @@ export function normalizeRole(role?: string | null): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function isRole(userRole: string | undefined | null, targetRole: string): boolean {
|
export function isRole(userRole: string | undefined | null, targetRole: string): boolean {
|
||||||
return normalizeRole(userRole) === targetRole.toUpperCase()
|
return normalizeRole(userRole) === normalizeRole(targetRole)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hasMinimumRole(userRole: string | undefined | null, requiredRole: string): boolean {
|
export function hasMinimumRole(userRole: string | undefined | null, requiredRole: string): boolean {
|
||||||
const userLvl = ROLE_LEVELS[normalizeRole(userRole)] || 0
|
const userLvl = ROLE_LEVELS[normalizeRole(userRole)] || 0
|
||||||
const reqLvl = ROLE_LEVELS[requiredRole.toUpperCase()] || 0
|
const reqLvl = ROLE_LEVELS[normalizeRole(requiredRole)] || 0
|
||||||
return userLvl >= reqLvl
|
return userLvl >= reqLvl
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,3 +43,32 @@ export function isCitizen(userRole?: string | null): boolean {
|
|||||||
export function canAccess(userRole: string | undefined | null, requiredRole: string): boolean {
|
export function canAccess(userRole: string | undefined | null, requiredRole: string): boolean {
|
||||||
return hasMinimumRole(userRole, requiredRole)
|
return hasMinimumRole(userRole, requiredRole)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function checkRoleAccess(userRole: string | undefined | null, requirement: MetaRoleRequirement | undefined): boolean {
|
||||||
|
if (!requirement) return true
|
||||||
|
|
||||||
|
const normalizedUserRole = normalizeRole(userRole)
|
||||||
|
if (!normalizedUserRole) return false
|
||||||
|
|
||||||
|
const requirements = Array.isArray(requirement) ? requirement : [requirement]
|
||||||
|
|
||||||
|
for (const req of requirements) {
|
||||||
|
const isNegated = req.startsWith('!')
|
||||||
|
|
||||||
|
const rawTarget = isNegated ? req.substring(1) : req
|
||||||
|
const targetRole = normalizeRole(rawTarget)
|
||||||
|
|
||||||
|
if (isNegated) {
|
||||||
|
console.log("negated", normalizedUserRole, targetRole)
|
||||||
|
if (normalizedUserRole === targetRole) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!hasMinimumRole(normalizedUserRole, targetRole)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user