Feature: endpoint GET /auth/me con identidad y permisos del usuario autenticado
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 delSecurityContext(sub del JWT ya validado porJwtRequestFilter), resuelve funcionario → si no, estudiante → si no, 401. Sin parámetros: siempre la cuenta propia, no se puede consultar la de otro. El armado depermisosreusa el criterio deCustomUsuarioDetailsService(soloRolPermisoACTIVO, sin el prefijoROLE_), deduplicado y ordenado. -
FuncionarioRepository/EstudianteRepository: nuevofindByIdConRolYPermisos(int id)conLEFT JOIN FETCHde rol/permisos (una sola query, sin N+1, sin depender de open-in-view;LEFTpara que un rol sin permisos igual resuelva conpermisos: []). - 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 deSecurityConfig(un@WebMvcTestno carga elSecurityConfigreal). -
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.