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.
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-7d32123d0f9cAdd Username and Password
Configure credentials in application.yml:
spring:
security:
user:
name: ming
password: 123456
roles: adminIn‑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.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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.
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.
