Mastering RBAC and Spring Security: From Basics to JWT Integration

This article provides a comprehensive guide to Role‑Based Access Control (RBAC) concepts, model classifications, and permission management, then walks through practical Spring Security setups—including basic usage, in‑memory authentication, JWT integration, JSON‑based login, password encryption, and database‑backed authentication, complete with code snippets and diagrams.

Java High-Performance Architecture
Java High-Performance Architecture
Java High-Performance Architecture
Mastering RBAC and Spring Security: From Basics to JWT Integration

RBAC Permission Analysis

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

Mind Map

What is RBAC

RBAC links users to roles and roles to permissions, allowing batch permission changes by modifying the role.

Model Classification

RBAC has four models: RBAC0, RBAC1, RBAC2, and RBAC3. RBAC0 is the most commonly used.

RBAC0

Two relationship types: many‑to‑one (a user has a single role) and many‑to‑many (a user can have multiple roles). Example: a user can be both an administrator and a finance officer.

RBAC1

Introduces role hierarchy (sub‑roles) and inheritance.

RBAC2 Model

Extends RBAC0 with additional constraints.

Role Mutually Exclusive

A user cannot hold two mutually exclusive roles simultaneously (e.g., accountant and auditor).

Cardinality Constraint

Limits the number of users that can be assigned to a role (e.g., only one CEO).

Prerequisite

A higher‑level role requires possession of a lower‑level role first.

Runtime Mutually Exclusive

A user may have two roles but cannot use them at the same time; they must switch contexts.

RBAC3 Model

Combines RBAC1 and RBAC2 into a unified model.

What is Permission

Permission is a collection of resources, such as page access, CRUD operations, etc.

User Group Usage

User groups allow batch assignment of roles to many users, reducing workload and improving manageability.

Spring Security Simple Usage

First add the dependency:

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

Then 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";
    }
}

Run the application and access the login page.

Enter username and password:

用户名:user
密码 984cccf2-ba82-468e-a404-7d32123d0f9c

Add Username and Password

Configure credentials in application.yml:

spring:
  security:
    user:
      name: ming
      password: 123456
      roles: admin

In‑Memory Authentication

Custom configuration extending WebSecurityConfigurerAdapter:

package com.example.demo.config;

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

Configure request interception:

package com.ming.demo.interceptor;

import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .anyRequest().permitAll()
            .and().formLogin().permitAll()
            .and().logout().permitAll();
    }
}

Spring Security JWT Integration

A demo that returns a JWT token after successful login.

Import Dependencies

Add JWT and Security dependencies (image omitted for brevity).

Create JwtUser implements UserDetails

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<? extends GrantedAuthority> authorities;
    // constructors, getters, and overridden methods omitted for brevity
}

Token Utility

package com.example.demo;

import io.jsonwebtoken.*;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.*;

public class JwtTokenUtil implements Serializable {
    private String secret;
    private Long expiration;
    private String header;
    // token generation, parsing, validation methods omitted for brevity
}

Authentication Filter

package com.example.demo;

import org.apache.commons.lang.StringUtils;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.*;
import java.io.IOException;

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

UserDetailsService Implementation

package com.example.demo;

import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.*;
import org.springframework.stereotype.Service;

@Service
public class JwtUserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    private UserMapper userMapper;
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        User user = userMapper.selectByUserName(s);
        if (user == null) {
            throw new UsernameNotFoundException(String.format("'%s' does not exist", s));
        }
        List<SimpleGrantedAuthority> authorities = user.getRoles().stream()
            .map(Role::getRolename)
            .map(SimpleGrantedAuthority::new)
            .collect(Collectors.toList());
        return new JwtUser(user.getUsername(), user.getPassword(), user.getState(), authorities);
    }
}

Login Service

package com.example.demo;

import org.springframework.security.authentication.*;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private UserDetailsService userDetailsService;
    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    @Override
    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));
    }
}

Final Config

@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
    @Autowired
    private UserDetailsService userDetailsService;
    @Autowired
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
    @Override
    public void configureAuthentication(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }
    @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().headers().cacheControl();
        http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
        http.authorizeRequests().requestMatchers(CorsUtils::isPreFlightRequest).permitAll();
    }
    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration cors = new CorsConfiguration();
        cors.setAllowCredentials(true);
        cors.addAllowedOrigin("*");
        cors.addAllowedHeader("*");
        cors.addAllowedMethod("*");
        source.registerCorsConfiguration("/**", cors);
        return new CorsFilter(source);
    }
}

Run and Get Token

Running the application returns a JWT token.

Spring Security JSON Login

Configure JSON login by overriding UsernamePasswordAuthenticationFilter.

Custom Authentication Filter

public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        if (MediaType.APPLICATION_JSON_UTF8_VALUE.equals(request.getContentType()) || MediaType.APPLICATION_JSON_VALUE.equals(request.getContentType())) {
            ObjectMapper mapper = new ObjectMapper();
            UsernamePasswordAuthenticationToken authRequest = null;
            try (InputStream is = request.getInputStream()) {
                AuthenticationBean bean = mapper.readValue(is, AuthenticationBean.class);
                authRequest = new UsernamePasswordAuthenticationToken(bean.getUsername(), bean.getPassword());
            } catch (IOException e) {
                authRequest = new UsernamePasswordAuthenticationToken("", "");
            } finally {
                setDetails(request, authRequest);
                return this.getAuthenticationManager().authenticate(authRequest);
            }
        } else {
            return super.attemptAuthentication(request, response);
        }
    }
}

Security Config

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.cors().and()
        .antMatcher("/**").authorizeRequests()
        .antMatchers("/", "/login**").permitAll()
        .anyRequest().authenticated()
        .and().formLogin().loginPage("/")
        .and().csrf().disable();
    http.addFilterAt(customAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}

@Bean
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;
}

Now JSON login works with Spring Security.

Spring Security Password Encryption

Define a BCrypt password encoder bean:

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

Use the encoder when storing and verifying passwords:

@Service
@Transactional
public class UserServiceImpl implements UserService {
    @Resource
    private UserRepository userRepository;
    @Resource
    private BCryptPasswordEncoder bCryptPasswordEncoder;
    @Override
    public User add(User user) {
        user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
        return userRepository.save(user);
    }
    @Override
    public ResultInfo login(User user) {
        User stored = userRepository.findByName(user.getName());
        if (stored == null) {
            return new ResultInfo("-1", "用户名不存在");
        }
        if (!bCryptPasswordEncoder.matches(user.getPassword(), stored.getPassword())) {
            return new ResultInfo("-1", "密码不正确");
        }
        return new ResultInfo("0", "登录成功");
    }
}

Database Authentication

Design tables for users, roles, and permissions (diagram omitted).

Configure Spring Security to use the custom UserDetailsService and BCrypt encoder:

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private UserService userService;
    @Bean
    public 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();
    }
}

Summary

The article thoroughly explains RBAC concepts and model variations, demonstrates basic and advanced Spring Security configurations—including in‑memory, JWT, JSON login, password encryption, and database authentication—providing complete code examples and diagrams for practical implementation.

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.

JavaAuthenticationJWTRBACspring-security
Java High-Performance Architecture
Written by

Java High-Performance Architecture

Sharing Java development articles and resources, including SSM architecture and the Spring ecosystem (Spring Boot, Spring Cloud, MyBatis, Dubbo, Docker), Zookeeper, Redis, architecture design, microservices, message queues, Git, etc.

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.