This is Part 3 of our implementation of SpringBoot roles and Privileges for our Inventory Management System (InventoryMS). In this part we would discuss and implement granted authorities in Spring Boot.
Parts 1 and 2 can be gotten from the links:
- SpringBoot Roles and Privileges – Standard Roles/Privileges in an Inventory Management System
- SpringBoot Roles and Privileges – The Data Model and API
- SpringBoot Roles and Privileges – Access Restriction Using Granted Authorities
1. What are Granted Authorities?
In Spring Security, we have the concept of Granted Authority. This represents a privilege or a permission granted to a user to perform a certain action.
What is difference between Role and Authority?
This two represent the same concept and are basically the same. The difference is how Spring Boot handle the prefixing. A role is expected to be prefixed with “ROLE_” but an authority is not.
For example, the authority “ADMIN” is the same as the role “ROLE_ADMIN”.
hasRole() vs hasAuthority()
This is also the same in concept. When you use hasRole(“ADMIN”), Spring Boot would expect that your role is named “ROLE_ADMIN”. However, if you use hasAuthority(“ADMIN”), Spring Boot would check if you have to role “ADMIN”.
In our InventoryMS project, we would be using hasAuthority().
2. Design the REST API Endpoint Pattern
To be able to achieve and efficient way to protect your API, you will have to design the routing pattern. What does this mean? It means you need some hierarchy for the API route. For example:
- top level: version number would (/v1)
- next level: modules for example, /orders, /products and /suppliers
- from here you can have methods GET, POST, PUT and DELETE
With this we would be able provide authorization at a granular level
3. Retrieving the User’s GrantedAuthorities
To be able to protect our REST API based on user roles, we would have to do the following:
return the users authorities (privileges) from UserPrincipal
Here, we would need to update the getAuthorities method of the UserPrincipal class so that it returns a lit of SimpleGrantedAuthorities.
@Override public Collection<? extends GrantedAuthority> getAuthorities() { return userPrivilegeAssignmentService.getUserPrivileges(user.getId()) .stream() .map(privilege -> new SimpleGrantedAuthority(privilege.getDescription())) // Use SimpleGrantedAuthority .collect(Collectors.toList()); }
4. Configure Authorization Rules
At this point we would have to configure the permission on the routes. So we would have to check if the user has the required authority before the request is permitted.
The following changes would need to be made:
... ... .authorizeHttpRequests(auth -> auth .requestMatchers("/register").permitAll() .requestMatchers("/login").permitAll() //Configuration for the product module .requestMatchers(HttpMethod.GET, "/api/v1/products").hasAuthority("VIEW_PRODUCT") .requestMatchers(HttpMethod.POST, "/api/v1/products").hasAuthority("CREATE_PRODUCT") .requestMatchers(HttpMethod.DELETE, "api/vi/product").hasAuthority("DELETE_PRODUCT") //Configuration for the order module .requestMatchers(HttpMethod.GET, "/api/v1/products").hasAuthority("VIEW_PRODUCT") .requestMatchers(HttpMethod.POST, "/api/v1/products").hasAuthority("CREATE_PRODUCT") .anyRequest().authenticated() ) ... ...
Then we would have to repeat this for all other roles we identified.
You could also create an enum type to hold these roles instead of using just strings. But I see no added benefits for taking this extra step.
Note that in our application, we use Roles only as grouping for privileges.
One thought on “InventoryMS – SpringBoot Roles and Privileges 3 (Implementing Granted Authorities)”