Skip to content

Feature: endpoint GET /auth/me con identidad y permisos del usuario autenticado

Agustín Cantero requested to merge pft/feature/auth-me-endpoint into master

Qué

Nuevo endpoint GET /auth/me: devuelve identidad y permisos del usuario del token, para que el frontend pueda manejar navegación y UI después del login.

Respuesta:

{
  "idUsuario": 12,
  "tipo": "FUNCIONARIO",
  "email": "ana.perez@utec.edu.uy",
  "nombre": "Ana",
  "apellido": "Pérez",
  "estado": "ACTIVO",
  "rol": "ADMINISTRADOR",
  "permisos": ["CREAR_INSTANCIA", "VER_COMENTARIO_CONFIDENCIAL_INSTANCIA"]
}

Por qué

Hoy la API no expone "quién soy" ni "qué puedo hacer", el frontend solo tiene el claim rol del JWT y los 403 que devuelve cada endpoint. Con /auth/me puede pintar el shell según tipo (FUNCIONARIO/ESTUDIANTE) y mostrar/ocultar acciones según permisos, sin adivinar.

El campo rol es el nom_rol (ej. ADMINISTRADOR), y va solo para mostrar y diagnóstico, el manejo fino se hace por permisos o por tipo.

Cambios

  • AuthController: @GetMapping("/me")authService.usuarioAutenticado(). Sin @PreAuthorize (solo requiere estar autenticado).
  • SecurityConfig: .requestMatchers(HttpMethod.GET, "/auth/me").authenticated() antes del /auth/** permitAll (gana el primer matcher que matchea).
  • AuthService.usuarioAutenticado() (@Transactional(readOnly = true)): saca el id del SecurityContext (sub del JWT ya validado por JwtRequestFilter), resuelve funcionario → si no, estudiante → si no, 401. Sin parámetros: siempre la cuenta propia, no se puede consultar la de otro. El armado de permisos reusa el criterio de CustomUsuarioDetailsService (solo RolPermiso ACTIVO, sin el prefijo ROLE_), deduplicado y ordenado.
  • FuncionarioRepository / EstudianteRepository: nuevo findByIdConRolYPermisos(int id) con LEFT JOIN FETCH de rol/permisos (una sola query, sin N+1, sin depender de open-in-view; LEFT para que un rol sin permisos igual resuelva con permisos: []).
  • Nuevos: dto/UsuarioAutenticadoDTO, model/TipoUsuario.

Acción requerida en el deploy

Ninguna. Sin cambios de schema, sin variables de entorno nuevas. Solo código.

Testing

  • Compila limpio. Suite completa: 716 tests, 0 failures (706 + 10 nuevos).
  • AuthMeControllerTest (@SpringBootTest, cadena de seguridad real): sin token → 401, token malformado → 401, token válido → 200 con la forma esperada. Es lo que cubre de verdad el matcher nuevo de SecurityConfig (un @WebMvcTest no carga el SecurityConfig real).
  • AuthServiceTest (unit): funcionario, estudiante, filtrado/dedupe/orden de permisos, rol sin permisos → [], id del token sin usuario → 401.
  • AuthControllerTest (@WebMvcTest): forma del JSON y que no exige ningún permiso específico.

Merge request reports

Loading