Contenido del curso
Configuración de seguridad
- 5

Configuración de Seguridad con Spring Security y Basic Authentication
06:32 min - 6

Cómo funciona el BasicAuthenticationFilter por dentro
11:50 min - 7

Deshabilitar CSRF en Spring Security con JWT
07:28 min - 8

Configuración global de CORS en Spring
12:11 min - 9

Configuración de Reglas de Acceso en Spring Security
07:45 min - 10

Creación de usuarios personalizados en Spring Security
07:06 min - 11

Creación y Gestión de Roles y Permisos en Aplicaciones Web
05:48 min
Autenticación con BD
Seguridad con JWT
Próximos pasos
Roles por usuario en Spring Security con JPA
Resumen
Asignar roles a usuarios en Spring Security te permite controlar qué endpoints puede consumir cada persona en tu API. Aquí aprenderás a crear una tabla de roles relacionada con tu tabla de usuarios, mapearla con JPA y conectarla a tu implementación de UserDetailsService para que los permisos dejen de ser uniformes y se segmenten correctamente.
Por qué necesitas una tabla de roles separada
Cuando autenticas usuarios desde la base de datos, asignar el mismo rol a todos rompe el control de acceso. La solución pasa por modelar los roles en una tabla independiente y traerlos junto con cada usuario.
La tabla user_role se relaciona con user y contiene tres atributos: username, role y granted_date. Los dos primeros forman una clave primaria compuesta, y el tercero registra desde cuándo ese usuario tiene ese permiso. Puedes generarla con Hibernate o con el script SQL de los recursos.
¿Qué es una clave primaria compuesta en JPA? Es una clave formada por dos o más columnas. En JPA la representas con una clase serializable anotada como
@IdClass, que implementaequalsyhashCode.
Cómo se mapea la entidad UserRoleEntity en JPA
Dentro del paquete entity, la clase UserRoleEntity declara username y role como parte de la clave primaria, y agrega grantedDate para saber desde cuándo aplica el permiso [01:30].
La anotación @IdClass apunta a UserRoleID, una clase auxiliar que contiene username y role, implementa Serializable y sobrescribe equals y hashCode. Además, la entidad mantiene una relación con el usuario, ya que cada permiso pertenece a un usuario puntual.
Cómo declarar la relación inversa en UserEntity
En UserEntity falta la contraparte. Crea una lista del tipo List<UserRoleEntity> llamada roles y anótala con @OneToMany, indicando mappedBy hacia el atributo user de UserRoleEntity. Esto cierra la relación bidireccional.
Usa FetchType.EAGER para que los roles se consulten automáticamente cada vez que recuperas un UserEntity. Así evitas hacer queries extra y siempre tienes los permisos disponibles cuando construyes el usuario de seguridad.
Cómo asignar roles existentes desde MySQL Workbench
Después de lanzar la aplicación, Hibernate crea la tabla en la base de datos. Refrescas en MySQL Workbench y verificas con un SELECT que la tabla existe pero está vacía.
Para replicar los roles que tenías en autenticación en memoria, inserta dos registros:
- Usuario
admincon roladmin. - Usuario
customercon rolcustomer. - Para
granted_dateescribesnow()sin comillas para que MySQL asigne la fecha actual al aplicar.
Un mismo usuario puede tener varios roles porque la clave primaria compuesta lo permite. Esa flexibilidad es clave cuando un perfil necesita combinar permisos.
Cómo transformar la lista de roles en el UserDetailsService
En UserSecurityService, el método que construye el UserDetails espera un arreglo de strings con los roles, pero UserEntity devuelve una lista de UserRoleEntity. Toca convertir.
El flujo queda así después de recuperar el usuario de la base de datos:
java String[] roles = userEntity.getRoles() .stream() .map(UserRoleEntity::getRole) .toArray(String[]::new);
Con stream recorres la lista, con map extraes el campo role que sí es string, y con toArray(String[]::new) obtienes el arreglo que necesita Spring Security. Ese arreglo se lo pasas al constructor del usuario que retornas [04:50].
¿Por qué usar method reference en el map? Porque
UserRoleEntity::getRolees más limpio que una lambda explícita y deja claro que solo extraes una propiedad de cada objeto.
Cómo verificar la segmentación de permisos en Postman
Reinicia la aplicación y prueba el endpoint /orders con Postman. Con admin y admin123 la petición responde 200, porque la configuración de seguridad permite ese rol en ese recurso.
Si intentas con el usuario customer, recibes un 403. La autenticación funciona, pero el filter chain no le otorga acceso a /orders. Así confirmas que los roles ya se leen desde la base de datos y no desde memoria.
Qué pasa cuando bloqueas una cuenta desde MySQL
Si cambias la propiedad locked del usuario admin a 1 y vuelves a lanzar la petición, recibes un 401. En el log aparece que no se encontró el usuario, porque la cuenta está bloqueada aunque la contraseña sea correcta.
Al regresar locked a 0, la cuenta se reactiva y la petición vuelve a responder 200. Este comportamiento depende de cómo Spring Security interpreta los flags de la cuenta dentro del UserDetails.
Con esto los permisos quedan segmentados por roles y tu API responde solo a quienes tienen acceso explícito. ¿Has tenido conflictos con FetchType.EAGER en relaciones grandes? Cuéntame cómo lo resolviste.