Home > Software engineering >  Spring Security: Best approach to deny access if a user doesn't have a relation with the entity
Spring Security: Best approach to deny access if a user doesn't have a relation with the entity

Time:12-23

I wasn't sure how to google this "issue" so I created this question instead.

The application I'm building has the following database structure (simplified for the example).

- Lab1
    - Users    
       - User1
       - User2
    - Products
       - Product1
- Lab2
    - Users 
       - User3
    - Products
       - Product2

Endpoints:
 - ../{labId}/products
 - ../products/{id}
 - ../{labId}/a
 - ../{labId}/b
 - ../{labId}/c
 - ../{labId}/d
 - ../{labId}/...

Users should only have access to data from the lab he's assigned to. User 3 shouldn't be able to get the product data from Product 1.

I've made a function that queries the database to check if a user is indeed associated with the requested lab, but I'll have to call this function on every single endpoint. Which will result in this function getting called a thousand times each minute, because every query a user does will be tied to a lab. This also makes for a lot of duplicate code.

The application is currently secured by using spring security with JWT and also has RBAC to deny certain users access to certain resources.

Is there any way to resolve this using annotations, is my database structure not optimal or is my approach correct?

Many thanks!

Edit: Example screenshot of an endpoint, productrepository is a basic JPA repository.

My concern is the duplication of the getLabAssociatedWithEntity / userBelongsToLab methods and was wondering if this is bad practice.

@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("Product not found with id: $id") }
}

CodePudding user response:

I think you can build associations between a user and products:

class User{
   Lab lab
   }

and the Product class you can have:

class Product{
   Lab lab;
}

class Lab{
   List<Product> productList
}

I didnt add the annotations but the idea is this, so if you have a certain instance of User, User1 and if the user belongs to a Lab, and a Lab has products, first you can get the lab of the user and then query the products of that lab (have lazy loading)

CodePudding user response:

I have decided to resolve this issue by caching the request to see if the user is associated with the lab. This way it doesn't slow down the application.

  • Related