Files
sgse-app/apps/web/src/lib/components/ProtectedRoute.svelte
deyvisonwanderley 2c3d231d20 refactor: enhance authentication and access control in ProtectedRoute component
- Updated the ProtectedRoute component to improve access control logic, including a timeout mechanism for handling authentication checks.
- Refactored the checkAccess function to streamline user access verification based on roles and authentication status.
- Added comments for clarity on the authentication flow and the use of the convexClient plugin in the auth.ts file.
- Improved the overall structure and readability of the code in auth.ts and ProtectedRoute.svelte.
2025-11-17 16:27:15 -03:00

105 lines
2.8 KiB
Svelte

<script lang="ts">
import { useQuery } from 'convex-svelte';
import { api } from '@sgse-app/backend/convex/_generated/api';
import { onMount } from 'svelte';
import type { Snippet } from 'svelte';
let {
children,
requireAuth = true,
allowedRoles = [],
maxLevel = 3,
redirectTo = '/'
}: {
children: Snippet;
requireAuth?: boolean;
allowedRoles?: string[];
maxLevel?: number;
redirectTo?: string;
} = $props();
let isChecking = $state(true);
let hasAccess = $state(false);
let timeoutId: ReturnType<typeof setTimeout> | null = null;
const currentUser = useQuery(api.auth.getCurrentUser, {});
// Usar $effect para reagir às mudanças na query
$effect(() => {
checkAccess();
});
function checkAccess() {
// Limpar timeout anterior se existir
if (timeoutId) {
clearTimeout(timeoutId);
timeoutId = null;
}
// Se a query ainda está carregando (undefined), aguardar
if (currentUser === undefined) {
isChecking = true;
hasAccess = false;
return;
}
// Se a query retornou dados, verificar autenticação
if (currentUser?.data) {
// Verificar roles
if (allowedRoles.length > 0) {
const hasRole = allowedRoles.includes(currentUser.data.role?.nome ?? '');
if (!hasRole) {
const currentPath = window.location.pathname;
window.location.href = `${redirectTo}?error=access_denied&route=${encodeURIComponent(currentPath)}`;
return;
}
}
// Verificar nível
if (currentUser.data.role?.nivel && currentUser.data.role.nivel > maxLevel) {
const currentPath = window.location.pathname;
window.location.href = `${redirectTo}?error=access_denied&route=${encodeURIComponent(currentPath)}`;
return;
}
// Se chegou aqui, permitir acesso
hasAccess = true;
isChecking = false;
return;
}
// Se não tem dados e requer autenticação, aguardar um pouco antes de redirecionar
// (pode estar carregando ainda)
if (requireAuth && !currentUser?.data) {
isChecking = true;
hasAccess = false;
// Aguardar 3 segundos antes de redirecionar (dar tempo para a query carregar)
timeoutId = setTimeout(() => {
// Verificar novamente antes de redirecionar
if (!currentUser?.data) {
const currentPath = window.location.pathname;
window.location.href = `${redirectTo}?error=auth_required&redirect=${encodeURIComponent(currentPath)}`;
}
}, 3000);
return;
}
// Se não requer autenticação, permitir acesso
if (!requireAuth) {
hasAccess = true;
isChecking = false;
}
}
</script>
{#if isChecking}
<div class="flex min-h-screen items-center justify-center">
<div class="text-center">
<span class="loading loading-spinner loading-lg text-primary"></span>
<p class="text-base-content/70 mt-4">Verificando permissões...</p>
</div>
</div>
{:else if hasAccess}
{@render children()}
{/if}