Sistema de Guards
Creative Minds implementa un robusto sistema de protección basado en guards que aseguran el acceso adecuado a diferentes partes de la aplicación.
Concepto de Guards
Los guards son clases que implementan lógica de protección y autorización. Pueden verificar:
- Autenticación del usuario
- Roles y permisos
- Estado de onboarding
- Suscripciones activas
- Otros requisitos de acceso
Implementación Base
Guard Base
// shared/utils/guard.ts
export class Guard {
constructor(
protected name: string
) {}
protected protect({
condition,
redirectTo
}: {
condition: boolean,
redirectTo: string
}) {
if (condition) {
redirect(redirectTo);
}
}
}Guards Específicos
1. Auth Guard
// modules/auth/guards/auth.guard.ts
class AuthGuard extends Guard {
constructor(
name: string,
private authService: AuthService
) {
super(name);
this.logger = new Logger(name + "Guard");
}
// Protección básica de autenticación
async protectByAuth({ redirectTo }: { redirectTo: string }) {
const { sub } = await this.authService.getCurrentUser();
this.protect({
redirectTo,
condition: !sub,
});
}
// Protección por rol
async protectByAuthAndRole({
roles,
redirectTo
}: ProtectByRoleProps) {
const { sub, role } = await this.authService.getCurrentUser();
// Verifica autenticación
this.protect({
redirectTo: redirectTo || "/login",
condition: !sub,
});
// Verifica rol
this.protect({
redirectTo: redirectTo || "/login",
condition: !role || !roles.includes(role),
});
}
}
export const authGuard = new AuthGuard("auth", authService);2. Onboarding Guard
// modules/onboarding/guards/onboarding.guard.ts
class OnboardingGuard extends Guard {
constructor(
name: string,
private onboardingService: OnboardingService
) {
super(name);
this.logger = new Logger(name + "Guard");
}
async protectByOnboarding({
redirectTo
}: {
redirectTo: string
}) {
const onboarding = await this.onboardingService.getCurrentUserOnboarding();
this.protect({
redirectTo,
condition: !onboarding?.completed,
});
}
}
export const onboardingGuard = new OnboardingGuard(
"onboarding",
onboardingService
);Uso en la Aplicación
1. En Layouts
// app/(core)/dashboard/layout.tsx
export default async function DashboardLayout({
children,
}: {
children: React.ReactNode
}) {
// Protección por autenticación
await authGuard.protectByAuth({
redirectTo: "/login",
});
// Protección por onboarding
await onboardingGuard.protectByOnboarding({
redirectTo: "/onboarding",
});
return (
<div className="flex h-screen">
<SidebarFeat />
{children}
</div>
);
}2. En Server Actions
// modules/users/actions/profile.action.ts
export async function updateProfileAction(data: ProfileData) {
// Verifica autenticación y rol
await authGuard.protectByAuthAndRole({
roles: ["employee", "admin"],
redirectTo: "/unauthorized"
});
// Procede con la actualización
return userService.updateProfile(data);
}Middleware Integration
El sistema de guards se complementa con el middleware de Next.js:
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
import { updateSession } from './providers/database/supabase/middleware'
export async function middleware(request: NextRequest) {
// Actualiza la sesión en cada request
return await updateSession(request)
}
export const config = {
matcher: [
// Excluye recursos estáticos
'/((?!_next/static|_next/image|favicon.ico).*)',
],
}Mejores Prácticas
-
Granularidad: Crear guards específicos para cada tipo de protección
-
Composición: Combinar múltiples guards cuando sea necesario
-
Logging: Mantener logs de intentos de acceso no autorizado
-
Mensajes claros: Proporcionar feedback útil al usuario
-
Flexibilidad: Permitir configuración de redirects y comportamientos
-
Performance: Minimizar llamadas innecesarias a servicios externos
Diagrama de Flujo
Este sistema de guards proporciona una capa de seguridad robusta y flexible, permitiendo proteger diferentes aspectos de la aplicación de manera modular y mantenible.