Information Security 18 min read

RBAC Permission Analysis and Spring Security JWT Integration Tutorial

This tutorial explains RBAC concepts and model classifications, demonstrates permission and user‑group management, and provides step‑by‑step guidance for implementing Spring Security with in‑memory authentication, JWT integration, JSON login, password encryption, and database authentication using Java code examples.

Architect
Architect
Architect
RBAC Permission Analysis and Spring Security JWT Integration Tutorial

This article introduces RBAC (Role‑Based Access Control), describing its purpose of linking users to roles and roles to permissions to simplify permission management.

It outlines the four RBAC models: RBAC0 (basic), RBAC1 (adds role hierarchy), RBAC2 (adds constraints such as mutually exclusive roles, cardinality, and prerequisites), and RBAC3 (combines RBAC1 and RBAC2 into a unified model).

The concept of permissions is clarified as a collection of resources, with examples of page access, data CRUD operations, and specific functional modules.

User groups are presented as a way to batch‑assign roles to many users, reducing administrative effort.

Spring Security Simple Usage

First, 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>

Define a test controller:

@RestController
@RequestMapping("/test")
public class Test {
    @RequestMapping("/test")
    public String test(){
        return "test";
    }
}

Configure HttpSecurity to permit all requests:

protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
        .anyRequest().permitAll()
        .and().formLogin().permitAll()
        .and().logout().permitAll();
}

JWT Integration with Spring Security

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 a JwtUser class implementing UserDetails :

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 token utility JwtTokenUtil for generating, parsing, refreshing, and validating JWT tokens:

public class JwtTokenUtil implements Serializable {
    private String secret;
    private Long expiration;
    private String header;
    // generateToken, getClaimsFromToken, getUsernameFromToken, isTokenExpired, refreshToken, validateToken methods
}

Define a filter JwtAuthenticationTokenFilter that extracts the token from the request header and sets the authentication context:

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);
    }
}

Implement JwtUserDetailsServiceImpl to load users from the database and convert roles to SimpleGrantedAuthority objects.

Provide a login service that authenticates the user and returns a JWT token:

@Service
public class UserServiceImpl implements UserService {
    @Autowired private AuthenticationManager authenticationManager;
    @Autowired private UserDetailsService userDetailsService;
    @Autowired private JwtTokenUtil jwtTokenUtil;
    public RetResult login(String username, String password) throws AuthenticationException {
        UsernamePasswordAuthenticationToken upToken = new UsernamePasswordAuthenticationToken(username, password);
        Authentication authentication = authenticationManager.authenticate(upToken);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        UserDetails userDetails = userDetailsService.loadUserByUsername(username);
        return new RetResult(RetCode.SUCCESS.getCode(), jwtTokenUtil.generateToken(userDetails));
    }
}

Configure the security chain to use the JWT filter and stateless session management:

@EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
    @Autowired private UserDetailsService userDetailsService;
    @Autowired private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
    @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
    @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); }
    @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }
    @Override protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and().authorizeRequests()
            .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
            .antMatchers("/auth/**").permitAll()
            .anyRequest().authenticated()
            .and().addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
    }
}

JSON Login Customization

Define a CustomAuthenticationFilter that reads JSON payloads for username and password:

public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
    @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        if (MediaType.APPLICATION_JSON_VALUE.equals(request.getContentType())) {
            try (InputStream is = request.getInputStream()) {
                AuthenticationBean bean = new ObjectMapper().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);
            }
        } else {
            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 storing them and to verify passwords during login:

@Bean public BCryptPasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }

// In service layer
user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
if (!bCryptPasswordEncoder.matches(inputPassword, storedPassword)) { /* handle failure */ }

Database Authentication

Configure WebSecurityConfigurerAdapter to use a custom UserDetailsService that loads users from the database and to protect URLs based on roles:

@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();
}

In summary, the article covers RBAC theory, model classifications, permission concepts, user‑group management, and provides a comprehensive, code‑rich guide to implementing authentication and authorization in Java using Spring Security, JWT, JSON login, password encryption, and database‑backed user stores.

JavaAccess ControlAuthenticationJWTRBACSpring SecurityPassword Encryption
Architect
Written by

Architect

Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.