es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Spring Security: Mejor enfoque para denegar el acceso si un usuario no tiene relación con la entidad.

No estaba seguro de cómo buscar este “problema”, así que en su lugar creé esta pregunta.

La aplicación que estoy construyendo tiene la siguiente estructura de base de datos (simplificada para el ejemplo).

- Lab1
    - Usuarios 
       - Usuario1
       - Usuario2
    - Productos
       - Producto1
- Lab2
    - Usuarios 
       - Usuario3
    - Productos
       - Producto2

Endpoints:
– ../{labId}/productos
– ../productos/{id}
– ../{labId}/a
– ../{labId}/b
– ../{labId}/c
– ../{labId}/d
– ../{labId}/…

Los usuarios solo deben tener acceso a los datos del laboratorio al que están asignados. El Usuario 3 no debería poder obtener los datos del producto Producto1.

He creado una función que consulta la base de datos para comprobar si un usuario está realmente asociado al laboratorio solicitado, pero tendré que llamar a esta función en cada uno de los puntos finales. Lo cual resultará en esta función siendo llamada mil veces cada minuto, ya que cada consulta que un usuario realiza estará vinculada a un laboratorio. Esto también genera mucho código duplicado.

La aplicación está actualmente asegurada mediante el uso de Spring Security con JWT y también tiene RBAC para denegar el acceso a ciertos recursos a determinados usuarios.

¿Existe alguna manera de resolver esto utilizando anotaciones? ¿Es mi estructura de base de datos óptima o es correcto mi enfoque?

¡Muchas gracias!

Edit: Ejemplo de captura de pantalla de un punto final, productrepository es un repositorio JPA básico.

Mi preocupación es la duplicación de los métodos getLabAssociatedWithEntity / userBelongsToLab y me preguntaba si esto es una mala práctica.

“`
@GetMapping("/{id}")
fun getProductById(@PathVariable id: Long): ResponseEntity<product> {
val lab = getLabAssociatedWithProduct(id)
if (userBelongsToLab(SecurityContextHolder.getContext().authentication.name, lab.id)) {
return ResponseEntity.ok().body(productService.getProductById(id))
}
return ResponseEntity(HttpStatus.UNAUTHORIZED)
}

Productservice
fun getProductById(id: Long): Product {
return productRepository.findById(id).orElseThrow { ResourceNotFoundException("Producto no encontrado con id: $id") }
}
“`

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Una forma de evitar llamar a la función varias veces y reducir el código duplicado es utilizar Spring AOP (Programación Orientada a Aspectos). Puedes crear un aspecto que intercepte los métodos del controlador y verifique si el usuario está asociado con el laboratorio solicitado antes de permitir el acceso. De esta manera, no es necesario llamar a la función en cada punto final y se puede eliminar el código duplicado.

    Otra opción es utilizar las anotaciones de seguridad a nivel de método de Spring Security, como @PreAuthorize o @PostAuthorize. Puedes definir reglas que verifiquen si el usuario está asociado con el laboratorio solicitado antes de permitir el acceso a métodos específicos.

    En cuanto a la estructura de la base de datos, parece estar bien para el escenario dado. Sin embargo, puedes considerar agregar una restricción de clave externa entre las tablas Lab y Product para asegurarte de que un producto esté asociado con un laboratorio.

    En general, tu enfoque es correcto y siempre es mejor garantizar la seguridad de tu aplicación que preocuparse por unas consultas adicionales.

Comments are closed.