Spring Security(5.x, 6.x ) RBAC访问控制
在 Spring Security 中,基于不同版本实现 RBAC(基于角色的访问控制)功能有一些不同的方式。RBAC 的基本原理是:定义用户、角色和权限的关系,并控制不同用户对资源的访问。
Spring Security 不同版本的实现主要在配置方法、注解支持、以及代码风格上有所不同。以下是不同版本的 RBAC 配置方式和实现思路。
https://docs.spring.io/spring-security/reference/index.html
Spring Security 5.x 及以前的版本
在 Spring Security 5.x 版本中,RBAC 的实现一般是通过 WebSecurityConfigurerAdapter
类来配置 URL 访问规则、角色、权限等。方法级的权限控制通过 @EnableGlobalMethodSecurity
注解开启。
1. 数据库表设计(通用)
RBAC 设计的数据库表包括 用户(User)、角色(Role) 和 权限(Permission)。基本表结构可以参考如下设计:
-- 用户表
CREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) UNIQUE NOT NULL,
password VARCHAR(100) NOT NULL,
enabled BOOLEAN DEFAULT TRUE
);
-- 角色表
CREATE TABLE roles (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
role_name VARCHAR(50) UNIQUE NOT NULL
);
-- 用户角色关联表(多对多)
CREATE TABLE user_roles (
user_id BIGINT,
role_id BIGINT,
PRIMARY KEY (user_id, role_id),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE
);
-- 权限表
CREATE TABLE permissions (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
permission_name VARCHAR(50) UNIQUE NOT NULL
);
-- 角色权限关联表(多对多)
CREATE TABLE role_permissions (
role_id BIGINT,
permission_id BIGINT,
PRIMARY KEY (role_id, permission_id),
FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE,
FOREIGN KEY (permission_id) REFERENCES permissions(id) ON DELETE CASCADE
);
2. WebSecurityConfigurerAdapter
配置类
WebSecurityConfigurerAdapter
是 Spring Security 5 及以前版本的主要配置方式。以下是配置方法:
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) // 开启方法级别的权限控制
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final UserDetailsService userDetailsService;
public SecurityConfig(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN") // 配置 URL 权限
.antMatchers("/user/**").hasAnyRole("USER", "ADMIN")
.anyRequest().authenticated() // 其他请求都需要认证
.and()
.formLogin()
.permitAll()
.and()
.logout()
.permitAll();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
3. 方法级别权限控制
启用方法级别的安全注解后,可以在服务层或控制器层方法上直接使用 @PreAuthorize
或 @Secured
注解来控制权限。
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
@Service
public class MyService {
@PreAuthorize("hasRole('ADMIN')")
public void adminMethod() {
// 只有 ADMIN 角色的用户可以访问
}
@PreAuthorize("hasAnyRole('ADMIN', 'USER')")
public void userOrAdminMethod() {
// 只有 ADMIN 或 USER 角色的用户可以访问
}
}
Spring Security 6.x 及以后的版本
Spring Security 6.x 中,WebSecurityConfigurerAdapter
已被弃用,推荐使用 SecurityFilterChain
配置和 @EnableMethodSecurity
注解。
1. SecurityFilterChain
配置类
不再继承 WebSecurityConfigurerAdapter
,而是使用 SecurityFilterChain
来配置安全规则。同时,方法级别的权限控制启用方式从 @EnableGlobalMethodSecurity
改为 @EnableMethodSecurity
。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
@EnableMethodSecurity // 启用方法级别的安全控制
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests()
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/user/**").hasAnyRole("USER", "ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.permitAll()
.and()
.logout()
.permitAll();
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
2. 使用 @PreAuthorize
或 @RolesAllowed
进行方法级别控制
在 Spring Security 6 中,@EnableMethodSecurity
启用后,仍可以使用 @PreAuthorize
等注解来实现方法级别的权限控制:
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
@Service
public class MyService {
@PreAuthorize("hasRole('ADMIN')")
public void adminMethod() {
// 只有 ADMIN 角色的用户可以访问
}
@PreAuthorize("hasAnyRole('ADMIN', 'USER')")
public void userOrAdminMethod() {
// 只有 ADMIN 或 USER 角色的用户可以访问
}
}
3. 配置基于角色的访问控制逻辑
基于角色的访问控制逻辑可以通过 SecurityFilterChain
中的 authorizeHttpRequests()
方法来配置,以匹配不同的 URL 路径。新的 requestMatchers()
方法替代了以前的 antMatchers()
方法,以更好地支持多种路径匹配。
小结
功能 | Spring Security 5.x | Spring Security 6.x |
---|---|---|
配置类 | WebSecurityConfigurerAdapter | SecurityFilterChain |
方法级权限控制注解启用 | @EnableGlobalMethodSecurity | @EnableMethodSecurity |
URL 匹配方法 | antMatchers() | requestMatchers() |
密码加密方式 | PasswordEncoder (如 BCrypt ) | PasswordEncoder (如 BCrypt ) |
总体来说,Spring Security 6.x 通过简化配置、弃用过时方法,使得 RBAC 的实现更加清晰简洁。