- 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.
105 lines
2.8 KiB
Svelte
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}
|