From c613c71f1e9c0ee422613acb67367aa220aa9c60 Mon Sep 17 00:00:00 2001 From: Gabriel Menezes Date: Thu, 5 Nov 2026 14:58:17 -0400 Subject: [PATCH] fix(auth): tratar credenciais invalidas com HTTP 401 e habilitar auto-login no cadastro --- .../InvalidCredentialsExceptionMapper.java | 23 +++++++++++++++++++ .../login/InvalidCredentialsException.java | 7 ++++++ .../usecase/auth/login/LoginUseCase.java | 4 ++-- frontend/src/lib/api.ts | 6 ++++- frontend/src/pages/AuthPage.tsx | 18 +++++++++++---- 5 files changed, 50 insertions(+), 8 deletions(-) create mode 100644 backend/src/main/java/net/beetechgroup/beetask/interfaceadapters/controllers/InvalidCredentialsExceptionMapper.java create mode 100644 backend/src/main/java/net/beetechgroup/beetask/usecase/auth/login/InvalidCredentialsException.java diff --git a/backend/src/main/java/net/beetechgroup/beetask/interfaceadapters/controllers/InvalidCredentialsExceptionMapper.java b/backend/src/main/java/net/beetechgroup/beetask/interfaceadapters/controllers/InvalidCredentialsExceptionMapper.java new file mode 100644 index 0000000..bdee375 --- /dev/null +++ b/backend/src/main/java/net/beetechgroup/beetask/interfaceadapters/controllers/InvalidCredentialsExceptionMapper.java @@ -0,0 +1,23 @@ +package net.beetechgroup.beetask.interfaceadapters.controllers; + +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.ext.ExceptionMapper; +import jakarta.ws.rs.ext.Provider; +import net.beetechgroup.beetask.usecase.auth.login.InvalidCredentialsException; + +import java.util.Map; + +@Provider +public class InvalidCredentialsExceptionMapper implements ExceptionMapper { + @Override + public Response toResponse(InvalidCredentialsException exception) { + return Response.status(Response.Status.UNAUTHORIZED) + .type(MediaType.APPLICATION_JSON) + .entity(Map.of( + "error", "Unauthorized", + "message", exception.getMessage() != null ? exception.getMessage() : "Credenciais inválidas" + )) + .build(); + } +} diff --git a/backend/src/main/java/net/beetechgroup/beetask/usecase/auth/login/InvalidCredentialsException.java b/backend/src/main/java/net/beetechgroup/beetask/usecase/auth/login/InvalidCredentialsException.java new file mode 100644 index 0000000..8cb1d78 --- /dev/null +++ b/backend/src/main/java/net/beetechgroup/beetask/usecase/auth/login/InvalidCredentialsException.java @@ -0,0 +1,7 @@ +package net.beetechgroup.beetask.usecase.auth.login; + +public class InvalidCredentialsException extends RuntimeException { + public InvalidCredentialsException(String message) { + super(message); + } +} diff --git a/backend/src/main/java/net/beetechgroup/beetask/usecase/auth/login/LoginUseCase.java b/backend/src/main/java/net/beetechgroup/beetask/usecase/auth/login/LoginUseCase.java index 6a134ef..2d69ea8 100644 --- a/backend/src/main/java/net/beetechgroup/beetask/usecase/auth/login/LoginUseCase.java +++ b/backend/src/main/java/net/beetechgroup/beetask/usecase/auth/login/LoginUseCase.java @@ -31,7 +31,7 @@ public class LoginUseCase { if (userOptional.isEmpty()) { LOGGER.warnf("Login failed because email %s was not found", input.email()); - throw new RuntimeException("Invalid credentials"); + throw new InvalidCredentialsException("E-mail ou senha incorretos."); } User user = userOptional.get(); @@ -56,7 +56,7 @@ public class LoginUseCase { if (!passwordMatches) { LOGGER.warnf("Login failed because password did not match for email %s", input.email()); - throw new RuntimeException("Invalid credentials"); + throw new InvalidCredentialsException("E-mail ou senha incorretos."); } LOGGER.infof("Login authenticated for user %s", input.email()); diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts index e41e096..9ea0353 100644 --- a/frontend/src/lib/api.ts +++ b/frontend/src/lib/api.ts @@ -55,8 +55,12 @@ export async function apiFetch(path: string, options: RequestOptions = {}): P const parsed = JSON.parse(text) if (parsed.message) { errorMessage = parsed.message - } else if (parsed.error) { + } else if (parsed.error && typeof parsed.error === 'string') { errorMessage = parsed.error + } else if (parsed.details) { + errorMessage = response.status >= 500 + ? 'Ocorreu um erro interno no servidor. Tente novamente em instantes.' + : parsed.details } } catch { // Usar texto puro diff --git a/frontend/src/pages/AuthPage.tsx b/frontend/src/pages/AuthPage.tsx index 06d2ccf..8e3969b 100644 --- a/frontend/src/pages/AuthPage.tsx +++ b/frontend/src/pages/AuthPage.tsx @@ -91,11 +91,19 @@ export const AuthPage = () => { try { await register(name, email, password) - setSuccessMessage('Conta criada com sucesso! Faça login para acessar seu workspace.') - setMode('login') - setSearchParams({ mode: 'login' }) - setPassword('') - setConfirmPassword('') + try { + const response = await login(email, password) + if (!response.organizations || response.organizations.length === 0) { + navigate('/organizations') + } else { + navigate('/dashboard') + } + return + } catch { + setSuccessMessage('Conta criada com sucesso! Faça login para acessar seu workspace.') + setMode('login') + setSearchParams({ mode: 'login' }) + } } catch (err: unknown) { const msg = err instanceof Error ? err.message : 'Erro ao criar conta. Tente novamente.' setErrorMessage(msg)