This tutorial will teach you how to implement Role-based access control in the new Spring Authorization Server. You will learn how to add a user role to a JWT token issued by Spring Authorization Server and configure Spring Resource Server to secure access to the API endpoint based on a user role.
1. Create, Run and Configure Spring Authorization Server
When writing this tutorial, I assumed that you are familiar with how to do the basic configuration of the new Spring Authorization Server. If you need to review how to create, run and do the basic configuration of the new Spring Authorization Server, read the Spring Authorization Server tutorial first.
2. Add User Role to JWT
At the time of writing this tutorial, Spring Authorization Server does not include user roles in JWT. If you decode JWT issued by the new Spring Authorization Server, you will find a “scope” claim but not user roles. This is because, by default, the resource server populates the authorities based on the “scope” claim.
If you need to include user roles in JWT, read the following tutorial, “Add Roles to JWT Issued by Spring Authorization Server“.
3. Map Roles Claim from JWT to Granted Authorities
Now that you have a “roles” claim in the JWT token, you can convert user roles into a list of Granted Authorities. To do that, you will need to implement a custom JwtRoleConverter. This implementation will need to be done in a Resource Server.
3.1 Implement Custom JwtRoleConverter
To implement the new JwtRoleConverter, add the following class to your Resource Server.
The method in this class will map the “roles” claim from the JWT token to a list of Granted Authorities in the Resource Server.
public class JwtRoleConverter implements Converter<Jwt, Collection> { @Override public Collection convert(Jwt jwt) { @SuppressWarnings("unchecked") List roles = (ArrayList) jwt.getClaims().get("roles"); if (roles == null || roles.isEmpty()) { return new ArrayList<>(); } return roles.stream().map(SimpleGrantedAuthority::new) .collect(Collectors.toList()); } }
Now that you have a method that maps the “roles” claim to a list of granted authorities, you can use it to configure the HttpSecurity object.
3.2 Configure HttpSecurity Object
To configure HttpSecurity object so that it can convert roles claim from the JWT access token to a list of granted authorities, we will need to create a new JwtAuthenticationConverter object.
JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter(); jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(new JwtRoleConverter());
Now we can use JwtAuthenticationConverter object to configure HttpSecurity object.
Notice that we use the jwtAuthenticationConverter() method to apply the JwtAuthenticationConverter object to HttpSecurity.
@Configuration @EnableWebSecurity @EnableMethodSecurity(prePostEnabled = true) public class WebSecurity{ @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter(); jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(new JwtRoleConverter()); http .authorizeHttpRequests(authz -> authz .anyRequest().authenticated()) .oauth2ResourceServer() .jwt() .jwtAuthenticationConverter(jwtAuthenticationConverter); return http.build(); } }
Notice that in the class above, I have used @EmableMethodSecurity to enable the Method Level Security. I can now use Spring’s method-level security annotations to secure any method in the controller class.
The below code example will demonstrate how to do it.
3.2 Secure API Endpoints
Now that I have enabled Spring’s Method-level security, I can secure any method in my controller class to require a user role. For example, let’s assume we have a method in the controller class that returns a list of orders. This method must be accessible only to users assigned the role name “user“. To do that, I will annotate the method in the controller class with the @PreAuthorize(“hasRole(‘user’)”) annotation.
@RestController public class OrdersController { @PreAuthorize("hasRole('user')") @GetMapping("/orders") public List<OrderRest> getOrders() { OrderRest order1 = new OrderRest(UUID.randomUUID().toString(), "product-id-1", "user-id-1", 1, OrderStatus.NEW); OrderRest order2 = new OrderRest(UUID.randomUUID().toString(), "product-id-2", "user-id-1", 1, OrderStatus.NEW); return Arrays.asList(order1, order2); }
I hope this tutorial is helpful to you.
For video lessons on how to secure your Spring Boot application with OAuth 2.0. and Spring Security 5, please checkout my complete video course OAuth 2.0. in Spring Boot applications.
Happy learning!