fix(auth): Block access to protected routes for users without 'active' status in supabase
This commit is contained in:
@@ -3,22 +3,42 @@ import { Navigate } from 'react-router-dom';
|
||||
import { useAuth } from '@/hooks/useAuth';
|
||||
import { useUserRole } from '@/hooks/useUserRole';
|
||||
|
||||
import { useUserProfile } from '@/hooks/useUserProfile';
|
||||
|
||||
interface ProtectedAdminRouteProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export const ProtectedAdminRoute: React.FC<ProtectedAdminRouteProps> = ({ children }) => {
|
||||
const { user, loading } = useAuth();
|
||||
const { user, loading: authLoading } = useAuth();
|
||||
const { isAdmin, loading: roleLoading } = useUserRole();
|
||||
const { profile, loading: profileLoading } = useUserProfile();
|
||||
|
||||
if (loading || roleLoading) {
|
||||
return <div>Carregando...</div>;
|
||||
const loading = authLoading || roleLoading || profileLoading;
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="flex items-center justify-center min-h-screen bg-background">
|
||||
<div className="text-muted-foreground">Carregando...</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
return <Navigate to="/auth" replace />;
|
||||
}
|
||||
|
||||
// Verificar se o usuário está ativo no sistema
|
||||
if (profile && profile.status !== 'active') {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center min-h-screen bg-background text-center p-4">
|
||||
<h1 className="text-2xl font-bold mb-4">Acesso Bloqueado</h1>
|
||||
<p className="text-muted-foreground mb-2">Seu usuário existe, mas encontra-se com status: <strong>{profile.status || 'pendente'}</strong>.</p>
|
||||
<p className="text-muted-foreground">Por favor, contate o administrador para aprovar o seu acesso.</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!isAdmin) {
|
||||
return <Navigate to="/dashboard" replace />;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
import React from 'react';
|
||||
import { Navigate } from 'react-router-dom';
|
||||
import { useAuth } from '@/hooks/useAuth';
|
||||
import { useUserProfile } from '@/hooks/useUserProfile';
|
||||
|
||||
interface ProtectedRouteProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export const ProtectedRoute: React.FC<ProtectedRouteProps> = ({ children }) => {
|
||||
const { user, loading } = useAuth();
|
||||
const { user, loading: authLoading } = useAuth();
|
||||
const { profile, loading: profileLoading } = useUserProfile();
|
||||
|
||||
const loading = authLoading || profileLoading;
|
||||
|
||||
// Mostrar loading enquanto carrega autenticação
|
||||
if (loading) {
|
||||
@@ -23,7 +27,16 @@ export const ProtectedRoute: React.FC<ProtectedRouteProps> = ({ children }) => {
|
||||
return <Navigate to="/auth" replace />;
|
||||
}
|
||||
|
||||
// Logto já valida o usuário via JWT/OIDC.
|
||||
// Não precisa de profile separado no Supabase.
|
||||
// Verificar se o usuário está ativo no sistema
|
||||
if (profile && profile.status !== 'active') {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center min-h-screen bg-background text-center p-4">
|
||||
<h1 className="text-2xl font-bold mb-4">Acesso Bloqueado</h1>
|
||||
<p className="text-muted-foreground mb-2">Seu usuário existe, mas encontra-se com status: <strong>{profile.status || 'pendente'}</strong>.</p>
|
||||
<p className="text-muted-foreground">Por favor, contate o administrador para aprovar o seu acesso.</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return <>{children}</>;
|
||||
};
|
||||
@@ -3,6 +3,8 @@ import { Navigate } from 'react-router-dom';
|
||||
import { useAuth } from '@/hooks/useAuth';
|
||||
import { useUserRole } from '@/hooks/useUserRole';
|
||||
|
||||
import { useUserProfile } from '@/hooks/useUserProfile';
|
||||
|
||||
interface ProtectedRouteByResourceProps {
|
||||
children: React.ReactNode;
|
||||
resourceKey: string;
|
||||
@@ -11,10 +13,13 @@ interface ProtectedRouteByResourceProps {
|
||||
export const ProtectedRouteByResource: React.FC<ProtectedRouteByResourceProps> = ({
|
||||
children,
|
||||
}) => {
|
||||
const { user, loading } = useAuth();
|
||||
const { user, loading: authLoading } = useAuth();
|
||||
const { isAdmin, loading: roleLoading } = useUserRole();
|
||||
const { profile, loading: profileLoading } = useUserProfile();
|
||||
|
||||
if (loading || roleLoading) {
|
||||
const loading = authLoading || roleLoading || profileLoading;
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="flex items-center justify-center min-h-screen">
|
||||
<div className="text-muted-foreground">Carregando...</div>
|
||||
@@ -26,6 +31,17 @@ export const ProtectedRouteByResource: React.FC<ProtectedRouteByResourceProps> =
|
||||
return <Navigate to="/auth" replace />;
|
||||
}
|
||||
|
||||
// Verificar se o usuário está ativo no sistema
|
||||
if (profile && profile.status !== 'active') {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center min-h-screen bg-background text-center p-4">
|
||||
<h1 className="text-2xl font-bold mb-4">Acesso Bloqueado</h1>
|
||||
<p className="text-muted-foreground mb-2">Seu usuário existe, mas encontra-se com status: <strong>{profile.status || 'pendente'}</strong>.</p>
|
||||
<p className="text-muted-foreground">Por favor, contate o administrador para aprovar o seu acesso.</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Migração pro Logto: todos usuários autenticados têm acesso aos recursos.
|
||||
// Sistema de permissões granulares fica pra depois.
|
||||
return <>{children}</>;
|
||||
|
||||
@@ -7,6 +7,7 @@ interface UserProfile {
|
||||
full_name: string | null;
|
||||
email: string | null;
|
||||
profile_image_url: string | null;
|
||||
status: string | null;
|
||||
}
|
||||
|
||||
export function useUserProfile() {
|
||||
@@ -21,6 +22,7 @@ export function useUserProfile() {
|
||||
setProfile(null);
|
||||
setLoading(false);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [user]);
|
||||
|
||||
const fetchUserProfile = async () => {
|
||||
@@ -30,7 +32,7 @@ export function useUserProfile() {
|
||||
try {
|
||||
const { data, error } = await supabase
|
||||
.from('profiles')
|
||||
.select('full_name, email, profile_image_url')
|
||||
.select('full_name, email, profile_image_url, status')
|
||||
.eq('id', user.id)
|
||||
.maybeSingle();
|
||||
|
||||
@@ -41,7 +43,8 @@ export function useUserProfile() {
|
||||
setProfile({
|
||||
full_name: user.user_metadata?.full_name || null,
|
||||
email: user.email || null,
|
||||
profile_image_url: null
|
||||
profile_image_url: null,
|
||||
status: null
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -50,7 +53,8 @@ export function useUserProfile() {
|
||||
setProfile({
|
||||
full_name: user.user_metadata?.full_name || null,
|
||||
email: user.email || null,
|
||||
profile_image_url: null
|
||||
profile_image_url: null,
|
||||
status: null
|
||||
});
|
||||
} finally {
|
||||
setLoading(false);
|
||||
|
||||
Reference in New Issue
Block a user