Este documento explica didaticamente como funciona o sistema de autenticação e autorização do SIGEST, desenvolvido com Next.js, TypeScript e JWT.
O SIGEST implementa um sistema completo de autenticação e autorização com as seguintes características:
O sistema utiliza next-auth para gerenciar sessões de usuário, com:
Além do Next-Auth, o sistema utiliza tokens JWT para autenticar chamadas às APIs:
joseO sistema implementa um controle de acesso baseado em papéis (RBAC):
Um middleware global intercepta requisições para:
Para proteger uma página, siga estes passos:
Localização da Página: Coloque a página dentro da pasta src/app/(authenticated)/:
src/
├── app/
│ ├── (authenticated)/
│ │ ├── dashboard/
│ │ ├── categorias/
│ │ ├── clientes/
│ │ └── ... outras páginas protegidas
Verificação de Autenticação no Componente: Use o hook useAuth para verificar o status:
'use client';
import { useEffect } from 'react';
import { useRouter } from 'next/navigation';
import { useAuth } from '../../../hooks/useAuth';
export default function PaginaProtegida() {
const { status, user } = useAuth();
const router = useRouter();
useEffect(() => {
if (status === 'unauthenticated') {
router.push('/login');
}
}, [status, router]);
if (status === 'loading') {
return <div>Carregando...</div>;
}
return (
<div>
<h1>Página Protegida</h1>
<p>Bem-vindo, {user?.name}</p>
{/* Conteúdo da página */}
</div>
);
}
import { useAuth } from '../../../hooks/useAuth';
import { usePermissions } from '../../../lib/permissions';
export default function PaginaComPermissoes() {
const { user } = useAuth();
const { canCreate, canDelete } = usePermissions(user?.role);
return (
<div>
<h1>Página com Permissões</h1>
{/* Botão visível apenas para quem pode criar */}
{canCreate('clients') && (
<button>Novo Cliente</button>
)}
{/* Ação disponível apenas para quem pode excluir */}
{canDelete('clients') && (
<button>Excluir Cliente</button>
)}
</div>
);
}
Para proteger um endpoint de API, siga estes passos:
Localização da API: Crie o arquivo dentro de src/app/api/:
src/
├── app/
│ ├── api/
│ │ ├── clients/
│ │ │ └── route.ts
│ │ ├── categories/
│ │ │ └── route.ts
│ │ └── ... outras APIs
Verificação do Token: O middleware já verifica o token automaticamente, então você só precisa acessar os dados do usuário na API:
// src/app/api/clients/route.ts
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
// O middleware já verificou o token e adicionou x-user-payload no header
const userPayload = request.headers.get('x-user-payload');
const user = userPayload ? JSON.parse(userPayload) : null;
// Agora você pode usar os dados do usuário (id, email, role)
console.log(`API acessada por: ${user.email} (${user.role})`);
// Implementar a lógica da API...
return NextResponse.json({ data: [] });
}
useAuth para obter o token:import { useAuth } from '../../../hooks/useAuth';
export default function ClientesPage() {
const { getToken } = useAuth();
const fetchClientes = async () => {
const token = await getToken();
if (!token) {
// Tratar erro de autenticação
return;
}
const response = await fetch('/api/clients', {
headers: {
'Authorization': `Bearer ${token}`
}
});
// Processar resposta...
};
return (
// Renderizar componente...
);
}
Os componentes podem implementar controle de acesso através do sistema de permissões:
// src/components/ActionButton.tsx
'use client';
import { useAuth } from '../hooks/useAuth';
import { usePermissions } from '../lib/permissions';
import { Button } from './ui/button';
import { SystemModuleType, ActionType } from '../lib/permissions';
interface ActionButtonProps {
module: SystemModuleType;
action: ActionType;
children: React.ReactNode;
onClick: () => void;
}
export function ActionButton({ module, action, children, onClick }: ActionButtonProps) {
const { user } = useAuth();
const { hasPermission } = usePermissions(user?.role);
if (!hasPermission(module, action)) {
return null; // Componente não é renderizado se não tiver permissão
}
return (
<Button onClick={onClick}>
{children}
</Button>
);
}
import { ActionButton } from '../../../components/ActionButton';
export default function ClientesPage() {
const handleNovoCliente = () => {
// Lógica para criar cliente
};
return (
<div>
<h1>Clientes</h1>
<ActionButton
module="clients"
action="create"
onClick={handleNovoCliente}
>
Novo Cliente
</ActionButton>
{/* Outros elementos da página */}
</div>
);
}
O middleware do SIGEST (src/middleware.ts) realiza as seguintes tarefas:
Para Páginas Normais:
getToken do Next-AuthPara APIs:
Authorization com o prefixo BearerverifyJWTx-user-payload para uso na APIUm token é uma string criptografada que contém informações específicas sobre o usuário e permissões:
header.payload.signatureUma sessão é um mecanismo para manter o estado do usuário entre múltiplas requisições:
No SIGEST, o Next-Auth é configurado para usar uma estratégia baseada em JWT para sessões:
session: {
strategy: 'jwt',
}
Isso significa que:
Uso de Sessão (via Next-Auth):
Uso de Token JWT (direto):
Não, tokens e sessões não são incompatíveis. Na verdade, eles se complementam no SIGEST:
AuthorizationCookies são apenas um mecanismo de armazenamento, enquanto tokens e sessões são conceitos de autenticação:
Cookies: São pequenos arquivos armazenados no navegador do usuário
No SIGEST:
useAuth()Authorization para APIsuseAuth() e envia no header AuthorizationO sistema também implementa:
secret para assinar e verificar tokens JWTO sistema de autenticação e autorização do SIGEST oferece uma solução completa e segura para:
Este documento serve como guia para entender como funciona o sistema de segurança e como implementar novas funcionalidades seguindo o mesmo padrão.