I am building an application that displays information from a database on a website. The application is secured using Spring Security and my users can have different roles. The records shall be displayed depending on the roles of the current user. For example I want to display books from a database. Role X can see only some books and role Y, too. But role ADMIN can see all books.
Now I wonder where and how the authorization happens. I thought the service layer would be a good place, but how can I query for books the roles of the current user have access to.
My tables look like this:
book (id, name)
role (id, name)
role_book (id, role_id, book_id)
Thus a query for the books would be SELECT b.id, b.name FROM book b, role r role_book rb WHERE b.id = rb.book_id AND r.id = rb.role_id AND r.name IN (<roles of the current user>). When the current user has the ADMIN role I would simply select all books in the database.
But how do I execute these queries in a Spring service method? I think that this is a common authorization task. Are there any Spring mechanisms to do this?
I would do a simple redesign which will also make the data layer more reusable. It would be like this.
Service Layer
Here we take the current user's roles and pass to the data layer.
Iterable<Book> findAllMyBooks(){
...
List<String> roles = new ArrayList<>();
Authentication authentication = SecurityContextHolder.getContext()getAuthentication();
for (GrantedAuthority auth : authentication.getAuthorities()) {
roles.add(auth.getAuthority());
}
bookRepository.findAllByRoles(roles);
...
}
Data Layer
Query for the Books based on roles. So you can use this to fetch books for non-logged in users later on in administration panels.
Please note that I didn't had time to checked the JPQL query. There can be an error in the 'ADMIN' IN (:roles). Kindly check this.
@Query("SELECT b FROM Book b INNER JOIN b.roles r WHERE r.name IN (:roles) OR 'ADMIN' IN (:roles)")
Iterable<Book> findAllByRoles(@Param("roles") List<String> roles);
Entity Model
Map Many to many relationship with Roles and Books
For method authorization you can for example use @PreAuthorize("hasRole('ROLE_USER')")
annotation on top of method, here's a link on the subject: http://docs.spring.io/spring-security/site/docs/3.0.x/reference/el-access.html
For checking the role of user you can also use
SecurityContextHolderAwareRequestWrapper.isUserInRole(String role)
in Spring Security 3.0
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With