In modern web applications, securing resources based on user roles is a crucial requirement. Role-Based Access Control in Spring Boot enables fine-grained access management by assigning specific permissions to roles rather than individual users. This approach simplifies permission handling and enhances security.
In this post, we will explore how to implement RBAC in Spring Boot using Spring Security, with a practical example that includes custom roles, protected endpoints, and method-level security.

๐ง Project Setup
Use Spring Initializr or your favorite tool to generate a Spring Boot project with the following dependencies:
- Spring Web
- Spring Security
- Spring Data JPA
- H2 Database (for demo purposes)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<!-- pom.xml --> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> </dependencies> |
๐ค User and Role Entities
Create the following JPA entities to represent users and their roles.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
@Entity public class Role { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; // e.g., ROLE_USER, ROLE_ADMIN } @Entity public class AppUser { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String username; private String password; @ManyToMany(fetch = FetchType.EAGER) private Set<Role> roles = new HashSet<>(); } |
๐ Spring Security Configuration
Configure Spring Security to load user roles and enforce access control.
UserDetailsService Implementation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
@Service public class CustomUserDetailsService implements UserDetailsService { @Autowired private UserRepository userRepository; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { AppUser user = userRepository.findByUsername(username) .orElseThrow(() -> new UsernameNotFoundException("User not found")); Set<GrantedAuthority> authorities = user.getRoles().stream() .map(role -> new SimpleGrantedAuthority(role.getName())) .collect(Collectors.toSet()); return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), authorities); } } |
SecurityConfig Class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
@Configuration @EnableWebSecurity @EnableMethodSecurity public class SecurityConfig { @Autowired private CustomUserDetailsService userDetailsService; @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeHttpRequests(auth -> auth .requestMatchers("/admin/**").hasRole("ADMIN") .requestMatchers("/user/**").hasAnyRole("USER", "ADMIN") .anyRequest().authenticated() ) .httpBasic(); return http.build(); } @Bean public AuthenticationManager authManager(HttpSecurity http) throws Exception { return http.getSharedObject(AuthenticationManagerBuilder.class) .userDetailsService(userDetailsService) .passwordEncoder(passwordEncoder()) .and() .build(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } } |
๐ Controller with Role-Based Access
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
@RestController @RequestMapping("/user") public class UserController { @GetMapping("/profile") public String userProfile() { return "Welcome User!"; } } @RestController @RequestMapping("/admin") public class AdminController { @GetMapping("/dashboard") public String adminDashboard() { return "Welcome Admin!"; } } |
๐งช Sample Data Initialization
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
@Component public class DataLoader implements CommandLineRunner { @Autowired private UserRepository userRepository; @Autowired private RoleRepository roleRepository; @Autowired private PasswordEncoder encoder; @Override public void run(String... args) { Role admin = roleRepository.save(new Role(null, "ROLE_ADMIN")); Role user = roleRepository.save(new Role(null, "ROLE_USER")); AppUser adminUser = new AppUser(); adminUser.setUsername("admin"); adminUser.setPassword(encoder.encode("admin123")); adminUser.setRoles(Set.of(admin)); AppUser normalUser = new AppUser(); normalUser.setUsername("user"); normalUser.setPassword(encoder.encode("user123")); normalUser.setRoles(Set.of(user)); userRepository.saveAll(List.of(adminUser, normalUser)); } } |
โ Testing the RBAC
Use Postman or curl to test:
1 2 3 4 5 6 7 8 |
# Admin access curl -u admin:admin123 http://localhost:8080/admin/dashboard # User access curl -u user:user123 http://localhost:8080/user/profile |
Try accessing /admin/dashboard
with a user account to verify that RBAC works.
๐ Conclusion
Implementing Role-Based Access Control in Spring Boot allows you to manage access cleanly and securely. By leveraging Spring Security and defining user roles, you can protect sensitive endpoints and delegate access only to the right users.
RBAC in Spring Boot is a scalable solution especially when combined with database-driven roles and method-level security.