RBAC Permission Analysis and Spring Security Integration with JWT
This article explains the concepts of role‑based access control (RBAC), compares RBAC models, shows how to configure permissions and user groups, and provides step‑by‑step code examples for integrating Spring Security with JWT, JSON login, password encryption and database authentication in Java backend applications.
RBAC Permission Analysis
RBAC (Role‑Based Access Control) is a permission model that assigns permissions to roles and then assigns users to those roles, simplifying permission management.
RBAC Model Classification
The RBAC models are divided into four levels:
RBAC0
Basic model with users‑to‑roles (many‑to‑many) and roles‑to‑permissions relationships.
RBAC1
Introduces role hierarchy (inheritance) allowing sub‑roles.
RBAC2
Adds constraints such as role separation of duty, cardinality, prerequisite roles, and runtime separation.
RBAC3
Combines RBAC0‑RBAC2 features into a unified model.
What Is a Permission?
A permission is a set of resources that can be accessed or modified, such as page access, CRUD operations, etc.
User Group Usage
User groups allow batch assignment of roles to many users, reducing management effort.
Spring Security Simple Usage
Add the Spring Security starter dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>2.3.1.RELEASE</version>
</dependency>Create a controller:
package com.example.demo.web;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/test")
public class Test {
@RequestMapping("/test")
public String test(){
return "test";
}
}Configure username and password in application.yml :
spring:
security:
user:
name: ming
password: 123456
roles: adminIn‑Memory Authentication
Define a configuration class extending WebSecurityConfigurerAdapter :
package com.example.demo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
PasswordEncoder passwordEncoder(){
return NoOpPasswordEncoder.getInstance();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin").password("123").roles("admin");
}
}HttpSecurity Configuration
Allow all requests for demonstration:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().permitAll()
.and().formLogin().permitAll()
.and().logout().permitAll();
}Spring Security + JWT Integration
Add JWT and Spring Security dependencies:
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>2.3.1.RELEASE</version>
</dependency>Create JwtUser implementing UserDetails and a JwtTokenUtil utility class for token generation, parsing, validation and refresh.
package com.example.demo;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
public class JwtUser implements UserDetails {
private String username;
private String password;
private Integer state;
private Collection
authorities;
// constructors, getters, and overridden methods omitted for brevity
}Implement a filter JwtAuthenticationTokenFilter that extracts the token from the request header, validates it and sets the authentication in the security context.
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
String authHeader = request.getHeader(jwtTokenUtil.getHeader());
if (authHeader != null && StringUtils.isNotEmpty(authHeader)) {
String username = jwtTokenUtil.getUsernameFromToken(authHeader);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (jwtTokenUtil.validateToken(authHeader, userDetails)) {
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
}
chain.doFilter(request, response);
}
}Configure the security chain to use the JWT filter and enable stateless session management.
JSON Login with Spring Security
Override UsernamePasswordAuthenticationFilter to read JSON payloads:
public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if (MediaType.APPLICATION_JSON_VALUE.equals(request.getContentType())) {
ObjectMapper mapper = new ObjectMapper();
try (InputStream is = request.getInputStream()) {
AuthenticationBean bean = mapper.readValue(is, AuthenticationBean.class);
UsernamePasswordAuthenticationToken authRequest =
new UsernamePasswordAuthenticationToken(bean.getUsername(), bean.getPassword());
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
} catch (IOException e) {
return super.attemptAuthentication(request, response);
}
}
return super.attemptAuthentication(request, response);
}
}Register the custom filter in the security configuration and set its processing URL to /login/self .
Password Encryption
Define a BCryptPasswordEncoder bean and use it to encode passwords before persisting them, and to verify passwords during login.
@Bean
public BCryptPasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}In the service layer:
user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
if (!bCryptPasswordEncoder.matches(inputPassword, storedPassword)) {
// handle invalid password
}Database Authentication
Configure WebSecurityConfigurerAdapter to use a custom UserDetailsService that loads users from the database and to protect URLs with role‑based rules.
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("admin")
.anyRequest().authenticated()
.and().formLogin().loginProcessingUrl("/login").permitAll()
.and().csrf().disable();
}Conclusion
The article covered RBAC concepts, model classifications, permission definition, user‑group management, and demonstrated practical implementations of Spring Security, including simple in‑memory authentication, JWT integration, JSON‑based login, password encryption with BCrypt, and database‑backed authentication, providing a comprehensive guide for building secure backend systems.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.