fix(auth): harden profile sync and fallback on non-uuid id; restore kong gateway
This commit is contained in:
+22
-5
@@ -24,16 +24,33 @@ import {
|
||||
// Sincroniza user Logto com profiles Supabase e retorna o UUID real do Supabase
|
||||
async function syncUserToProfile(user: LogtoUser): Promise<string> {
|
||||
if (!user?.sub) return user.sub;
|
||||
const email = user.email || `${user.username || 'user'}@logto.local`;
|
||||
const email = (user.email || `${user.username || 'user'}@logto.local`).trim();
|
||||
|
||||
try {
|
||||
// 1. Tenta buscar o perfil existente pelo email
|
||||
const { data: existing } = await supabase
|
||||
// 1. Tenta buscar o perfil existente pelo email (case-insensitive)
|
||||
let { data: existing, error: selectError } = await supabase
|
||||
.from('profiles')
|
||||
.select('id')
|
||||
.eq('email', email)
|
||||
.ilike('email', email)
|
||||
.maybeSingle();
|
||||
|
||||
// Em caso de falha transitória de rede, faz 1 retry rápido antes de desistir
|
||||
if (selectError) {
|
||||
await new Promise((r) => setTimeout(r, 800));
|
||||
const retry = await supabase
|
||||
.from('profiles')
|
||||
.select('id')
|
||||
.ilike('email', email)
|
||||
.maybeSingle();
|
||||
existing = retry.data;
|
||||
selectError = retry.error;
|
||||
}
|
||||
|
||||
if (selectError) {
|
||||
console.warn('Erro de rede ao consultar profile no Supabase:', selectError);
|
||||
return user.sub;
|
||||
}
|
||||
|
||||
let profileId = existing?.id;
|
||||
|
||||
// 2. Se existe, atualizamos o nome e retornamos o UUID
|
||||
@@ -47,7 +64,7 @@ async function syncUserToProfile(user: LogtoUser): Promise<string> {
|
||||
return profileId;
|
||||
}
|
||||
|
||||
// 3. Se não existir, criamos um novo com um UUID gerado
|
||||
// 3. Se confirmadamente não existir, criamos um novo com um UUID gerado
|
||||
profileId = crypto.randomUUID();
|
||||
const { error: insertError } = await supabase.from('profiles').insert({
|
||||
id: profileId,
|
||||
|
||||
@@ -11,7 +11,8 @@ export const useUserFunction = () => {
|
||||
queryFn: async () => {
|
||||
if (!user?.id) return null;
|
||||
|
||||
const { data, error } = await supabase
|
||||
const isValidUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(user.id || '');
|
||||
let query = supabase
|
||||
.from('profiles')
|
||||
.select(`
|
||||
function_id,
|
||||
@@ -19,9 +20,17 @@ export const useUserFunction = () => {
|
||||
name,
|
||||
description
|
||||
)
|
||||
`)
|
||||
.eq('id', user.id)
|
||||
.single();
|
||||
`);
|
||||
|
||||
if (isValidUuid) {
|
||||
query = query.eq('id', user.id);
|
||||
} else if (user.email) {
|
||||
query = query.ilike('email', user.email.trim());
|
||||
} else {
|
||||
query = query.eq('id', user.id);
|
||||
}
|
||||
|
||||
const { data, error } = await query.maybeSingle();
|
||||
|
||||
if (error) {
|
||||
console.error('Erro ao buscar função do usuário:', error);
|
||||
|
||||
@@ -24,26 +24,56 @@ export function useUserPermissions() {
|
||||
|
||||
// Load user permissions
|
||||
const loadUserPermissions = useCallback(async () => {
|
||||
if (!user?.id) {
|
||||
if (!user?.id && !user?.email) {
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
console.log(`🔄 Loading permissions for user: ${user.email}`);
|
||||
const isUuid = Boolean(user.id && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(user.id));
|
||||
|
||||
// Load functional permissions from user privilege
|
||||
const { data: profile } = await supabase
|
||||
// Load functional permissions from user privilege (by UUID or fallback by email)
|
||||
let profileQuery = supabase
|
||||
.from('profiles')
|
||||
.select(`
|
||||
id,
|
||||
privilege_id,
|
||||
privileges!inner (
|
||||
name,
|
||||
permissions
|
||||
)
|
||||
`);
|
||||
|
||||
if (isUuid) {
|
||||
profileQuery = profileQuery.eq('id', user.id);
|
||||
} else if (user.email) {
|
||||
profileQuery = profileQuery.ilike('email', user.email.trim());
|
||||
} else {
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
let { data: profile } = await profileQuery.maybeSingle();
|
||||
|
||||
// Se buscou por UUID e não achou, tenta fallback por email
|
||||
if (!profile && isUuid && user.email) {
|
||||
const retryByEmail = await supabase
|
||||
.from('profiles')
|
||||
.select(`
|
||||
id,
|
||||
privilege_id,
|
||||
privileges!inner (
|
||||
name,
|
||||
permissions
|
||||
)
|
||||
`)
|
||||
.eq('id', user.id)
|
||||
.single();
|
||||
.ilike('email', user.email.trim())
|
||||
.maybeSingle();
|
||||
profile = retryByEmail.data;
|
||||
}
|
||||
|
||||
const resolvedUserId = profile?.id || (isUuid ? user.id : null);
|
||||
|
||||
if (profile?.privileges?.permissions) {
|
||||
// Safe type conversion with validation
|
||||
@@ -61,10 +91,11 @@ export function useUserPermissions() {
|
||||
}
|
||||
|
||||
// Load specific resource permissions
|
||||
if (resolvedUserId) {
|
||||
const { data: resourcePerms } = await supabase
|
||||
.from('user_interface_permissions')
|
||||
.select('resource_key, permission')
|
||||
.eq('user_id', user.id);
|
||||
.eq('user_id', resolvedUserId);
|
||||
|
||||
if (resourcePerms) {
|
||||
const permsMap = resourcePerms.reduce((acc, perm) => {
|
||||
@@ -74,13 +105,14 @@ export function useUserPermissions() {
|
||||
setResourcePermissions(permsMap);
|
||||
console.log('✅ Resource permissions loaded:', permsMap);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Error loading permissions:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [user?.id]);
|
||||
}, [user?.id, user?.email]);
|
||||
|
||||
useEffect(() => {
|
||||
loadUserPermissions();
|
||||
|
||||
@@ -30,11 +30,20 @@ export function useUserProfile() {
|
||||
|
||||
setLoading(true);
|
||||
try {
|
||||
const { data, error } = await supabase
|
||||
const isValidUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(user.id || '');
|
||||
let query = supabase
|
||||
.from('profiles')
|
||||
.select('full_name, email, profile_image_url, status')
|
||||
.eq('id', user.id)
|
||||
.maybeSingle();
|
||||
.select('full_name, email, profile_image_url, status');
|
||||
|
||||
if (isValidUuid) {
|
||||
query = query.eq('id', user.id);
|
||||
} else if (user.email) {
|
||||
query = query.ilike('email', user.email.trim());
|
||||
} else {
|
||||
query = query.eq('id', user.id);
|
||||
}
|
||||
|
||||
const { data, error } = await query.maybeSingle();
|
||||
|
||||
if (!error && data) {
|
||||
setProfile(data);
|
||||
|
||||
Reference in New Issue
Block a user