Mastering RBAC with Spring Security and JWT: A Complete Guide

This tutorial walks through RBAC fundamentals, model classifications (RBAC0‑3), permission and user‑group concepts, then demonstrates practical Spring Security setups including in‑memory authentication, JWT integration, JSON‑based login, password encryption with BCrypt, and database‑backed authentication, providing complete code examples.

Su San Talks Tech
Su San Talks Tech
Su San Talks Tech
Mastering RBAC with Spring Security and JWT: A Complete Guide

RBAC Permission Analysis

RBAC (Role‑Based Access Control) is a permission model that assigns permissions to roles and users to roles, simplifying management and reducing security risks.

Mind Map

RBAC mind map
RBAC mind map

What is RBAC

RBAC defines roles, users, and permissions; a user can have multiple roles, and a role can have multiple permissions, allowing efficient permission management.

Model Classification

RBAC0

Basic model with user‑to‑role and role‑to‑permission relationships. Example: a user may hold both administrative and financial roles.

RBAC1

Introduces role hierarchy (inheritance) and child roles.

RBAC2

Adds constraints such as mutually exclusive roles, cardinality limits, prerequisites, and runtime separation of duties.

RBAC3

Combines RBAC0‑2 features into a unified model.

What is Permission

Permission is a set of resources that can be accessed or manipulated, such as page access, CRUD operations, etc.

User Group Usage

User groups allow batch assignment of roles to many users, simplifying large‑scale permission management.

Spring Security Basic Usage

Add the Spring Security starter dependency:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

Create a simple 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 in‑memory authentication:

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 example to permit all requests:

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>

Implement JwtUser that implements UserDetails, a JwtTokenUtil for token generation/validation, a JwtAuthenticationTokenFilter to extract the token, and a custom UserDetailsService.

package com.example.demo;

public class JwtUser implements UserDetails {
    private String username;
    private String password;
    private Integer state;
    private Collection<? extends GrantedAuthority> authorities;
    // constructors, getters, and overridden methods...
}
package com.example.demo;

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

Filter example:

package com.example.demo;

@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 = this.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);
    }
}

Security configuration to use the filter and stateless sessions:

@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
    @Autowired private UserDetailsService userDetailsService;
    @Autowired private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    @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().headers().cacheControl();

        http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
    }
}

JSON Login with Custom Filter

Override UsernamePasswordAuthenticationFilter to read JSON payload:

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);
            }
        } else {
            return super.attemptAuthentication(request, response);
        }
    }
}

Register the custom filter in the security config:

@Bean
public CustomAuthenticationFilter customAuthenticationFilter() throws Exception {
    CustomAuthenticationFilter filter = new CustomAuthenticationFilter();
    filter.setAuthenticationSuccessHandler(new SuccessHandler());
    filter.setAuthenticationFailureHandler(new FailureHandler());
    filter.setFilterProcessesUrl("/login/self");
    filter.setAuthenticationManager(authenticationManagerBean());
    return filter;
}

Password Encryption

Define a BCryptPasswordEncoder bean and use it when storing or checking passwords:

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

Service example:

@Service
public class UserServiceImpl implements UserService {
    @Resource private UserRepository userRepository;
    @Resource private BCryptPasswordEncoder bCryptPasswordEncoder;

    public User add(User user) {
        user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
        return userRepository.save(user);
    }

    public ResultInfo login(User user) {
        User dbUser = userRepository.findByName(user.getName());
        if (dbUser == null) {
            return new ResultInfo("-1", "用户名不存在");
        }
        if (!bCryptPasswordEncoder.matches(user.getPassword(), dbUser.getPassword())) {
            return new ResultInfo("-1", "密码不正确");
        }
        return new ResultInfo("0", "登录成功");
    }
}

Database Authentication

Configure Spring Security to load users from the database and protect admin URLs:

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired private UserService userService;

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

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService);
    }

    @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 explains RBAC concepts, various RBAC models, permission and user‑group management, and demonstrates how to implement authentication and authorization in Spring Boot using Spring Security, JWT, JSON login, password encryption, and database‑backed user details.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaAuthenticationJWTAuthorizationRBACspring-security
Su San Talks Tech
Written by

Su San Talks Tech

Su San, former staff at several leading tech companies, is a top creator on Juejin and a premium creator on CSDN, and runs the free coding practice site www.susan.net.cn.

0 followers
Reader feedback

How this landed with the community

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.