Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to authorize the service layer of a Spring application?

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?

like image 466
stevecross Avatar asked Dec 06 '25 11:12

stevecross


2 Answers

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

like image 191
Faraj Farook Avatar answered Dec 08 '25 01:12

Faraj Farook


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

like image 26
allu Avatar answered Dec 08 '25 01:12

allu



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!