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

package com.pbn.demo013.config;import com.alibaba.fastjson2.JSON;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;import java.util.HashMap;import static org.springframework.security.config.Customizer.withDefaults;@Configuration
@EnableWebSecurity//Spring项目总需要添加此注解,SpringBoot项目中不需要
public class WebSecurityConfig {/*过滤链*/@Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {//authorizeRequests():开启授权保护//anyRequest():对所有请求开启授权保护//authenticated():// 3用户-角色-资源 开启授权保护/* http.authorizeRequests(authorize -> authorize//具有管理员角色的用户可以访问/user/**.requestMatchers("/user/**").hasRole("ADMIN")//对所有请求开启授权保护.anyRequest()//已认证的请求会被自动授权.authenticated());*/
//       硬编码 2 用户-权限-资源
//        http.authorizeRequests(
//                authorize -> authorize
//                        //具有USER_LIST权限的用户可以访问/user/list
//                        .requestMatchers("/user/list").hasAuthority("USER_LIST")
//                        //具有USER_ADD权限的用户可以访问/user/add
//                        .requestMatchers("/user/add").hasAuthority("USER_ADD")
//                        //对所有请求开启授权保护
//                        .anyRequest()
//                        //已认证的请求会被自动授权
//                        .authenticated()
//        );//        ----1 默认权限http.authorizeRequests(authorize -> authorize.anyRequest().authenticated());
//                .formLogin(withDefaults()); //表单授权方式  //3个
//        登录认证http.formLogin(form -> {form.loginPage("/login").permitAll() //登录页面无需授权即可访问.usernameParameter("username") //自定义表单用户名参数,默认是username.passwordParameter("password") //自定义表单密码参数,默认是password.failureUrl("/login?error") //登录失败的返回地址.successHandler(new MyAuthenticationSuccessHandler()) //认证成功时的处理.failureHandler(new MyAuthenticationFailureHandler()); //认证失败时的处理}); //使用表单授权方式
//                .httpBasic(withDefaults());//基本授权方式//关闭csrf攻击防御http.csrf((csrf) -> {csrf.disable();});
//登出http.logout(logout -> {logout.logoutSuccessHandler(new MyLogoutSuccessHandler()); //注销成功时的处理});
//跨域处理http.cors(withDefaults());
//会话管理 单个并发http.sessionManagement(session -> {session.maximumSessions(1).expiredSessionStrategy(new MySessionInformationExpiredStrategy());});//        //错误处理
//        http.exceptionHandling(exception -> {
//            exception.authenticationEntryPoint(new MyAuthenticationEntryPoint());//请求未认证的接口
//        });//错误处理 授权异常 request处理http.exceptionHandling(exception -> {exception.authenticationEntryPoint(new MyAuthenticationEntryPoint());//请求未认证的接口
//            匿名内部类,lambda
//            exception.accessDeniedHandler(new MyAccessDeniedHandler());exception.accessDeniedHandler((request, response, e) -> { //请求未授权的接口//创建结果对象HashMap result = new HashMap();result.put("code", -1);result.put("message", "没有权限");//转换成json字符串String json = JSON.toJSONString(result);//返回响应response.setContentType("application/json;charset=UTF-8");response.getWriter().println(json);});});return http.build();}
}

DBUserDetailsManager 是 Spring Security 中的一个实现类

它实现了 UserDetailsManagerUserDetailsPasswordService 接口。这两个接口分别提供了对用户数据的操作方法和密码处理的方法。DBUserDetailsManager 为开发者提供了一套完整的用户管理解决方案,包括用户账户的创建、删除、更新以及密码管理等功能,特别适用于需要基于数据库进行用户认证和授权的应用场景。通过实现 UserDetailsManagerUserDetailsPasswordService 接口,DBUserDetailsManager 能够很好地集成到 Spring Security 的安全框架中,提供强大的用户安全管理能力。

UserDetailsManager

UserDetailsManager 接口定义了一系列用于管理用户账户的方法,包括创建、删除、更新用户信息等。这些方法允许应用程序动态地管理用户账户,而不需要重启应用或手动修改数据库。具体来说,UserDetailsManager 提供了以下功能:

  • createUser(UserDetails user): 创建一个新的用户。
  • updateUser(UserDetails user): 更新现有的用户信息。
  • deleteUser(String username): 删除指定用户名的用户。
  • changePassword(String oldPassword, String newPassword): 允许用户更改自己的密码。
  • userExists(String username): 检查指定的用户名是否存在。

UserDetailsPasswordService

UserDetailsPasswordService 接口提供了一个方法,用于处理用户密码的更新。当用户尝试更改密码时,可以通过这个服务来更新数据库中的密码。这个接口的主要方法是:

  • UserDetails updatePassword(UserDetails user, String newPassword): 更新用户的密码,并返回更新后的 UserDetails 对象。

DBUserDetailsManager

DBUserDetailsManagerUserDetailsManagerUserDetailsPasswordService 的实现类,它提供了具体的实现,以便于在基于数据库的用户管理系统中使用。DBUserDetailsManager 通常会与一个 JdbcUserDetailsManager 或其他数据访问对象(DAO)一起工作,以实际地与数据库交互,执行用户管理操作。

  • 数据源配置DBUserDetailsManager 需要配置一个数据源(DataSource),以便连接到数据库。
  • 用户表结构:它假设数据库中存在一个符合Spring Security要求的用户表结构,包括用户名、密码、权限等字段。
  • 密码编码DBUserDetailsManager 支持使用不同的密码编码器(如BCryptPasswordEncoder),以安全的方式存储和验证用户密码。
package com.pbn.demo013.config;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.pbn.demo013.entity.User;
import com.pbn.demo013.mapper.UserMapper;
import jakarta.annotation.Resource;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsPasswordService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.provisioning.UserDetailsManager;
import org.springframework.stereotype.Component;import java.util.ArrayList;
import java.util.Collection;@Component
public class DBUserDetailsManager implements UserDetailsManager, UserDetailsPasswordService {@Resourceprivate UserMapper userMapper;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("username", username);User user = userMapper.selectOne(queryWrapper);if (user == null) {throw new UsernameNotFoundException(username);} else {
//            Collection<GrantedAuthority> authorities = new ArrayList<>();//            Collection<GrantedAuthority> authorities = new ArrayList<>();
//            authorities.add(()->"USER_LIST");
//            authorities.add(()->"USER_ADD");//            return new org.springframework.security.core.userdetails.User(
//                    user.getUsername(),
//                    user.getPassword(),
//                    user.getEnabled(),
//                    true, //用户账号是否过期
//                    true, //用户凭证是否过期
//                    true, //用户是否未被锁定
//                    authorities); //权限列表return org.springframework.security.core.userdetails.User.withUsername(user.getUsername()).password(user.getPassword())
//                    .roles("ADMIN")
//                    .roles("ADMIN1").authorities("USER_ADD", "USER_UPDATE") //roles,authorities相互覆盖.build();}}@Overridepublic UserDetails updatePassword(UserDetails user, String newPassword) {return null;}@Overridepublic void createUser(UserDetails userDetails) {User user = new User();user.setUsername(userDetails.getUsername());user.setPassword(userDetails.getPassword());user.setEnabled(true);userMapper.insert(user);}@Overridepublic void updateUser(UserDetails user) {}@Overridepublic void deleteUser(String username) {}@Overridepublic void changePassword(String oldPassword, String newPassword) {}@Overridepublic boolean userExists(String username) {return false;}
}
2. 使用 @PreAuthorize@RolesAllowed 进行方法级别控制

在 Spring Security 6 中,@EnableMethodSecurity 启用后,仍可以使用 @PreAuthorize 等注解来实现方法级别的权限控制:

package com.pbn.demo013.controller;import com.pbn.demo013.entity.User;
import com.pbn.demo013.service.UserService;
import jakarta.annotation.Resource;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.web.bind.annotation.*;import java.util.List;@RestController
@RequestMapping("/user")
@EnableMethodSecurity //方法的授权
public class UserController {@Resourcepublic UserService userService;@PreAuthorize("hasRole('ADMIN') and authentication.name == 'admim'")@GetMapping("/list")public List<User> getList(){return userService.list();}@PreAuthorize("hasAuthority('USER_ADD')")@PostMapping("/add")public void add(@RequestBody User user){userService.saveUserDetails(user);}}
3. 配置基于角色的访问控制逻辑

基于角色的访问控制逻辑可以通过 SecurityFilterChain 中的 authorizeHttpRequests() 方法来配置,以匹配不同的 URL 路径。新的 requestMatchers() 方法替代了以前的 antMatchers() 方法,以更好地支持多种路径匹配。

小结

功能Spring Security 5.xSpring Security 6.x
配置类WebSecurityConfigurerAdapterSecurityFilterChain
方法级权限控制注解启用@EnableGlobalMethodSecurity@EnableMethodSecurity
URL 匹配方法antMatchers()requestMatchers()
密码加密方式PasswordEncoder(如 BCryptPasswordEncoder(如 BCrypt

总体来说,Spring Security 6.x 通过简化配置、弃用过时方法,使得 RBAC 的实现更加清晰简洁。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/58740.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unity 如何优雅的限定文本长度, 包含对特殊字符,汉字,数字的处理。实际的案例包括 用户昵称

常规限定文本长度 ( 通过 UntiyEngine.UI.Inputfiled 附带的长度限定 ) 痛点1 无法对中文&#xff0c;数字&#xff0c;英文进行识别&#xff0c;同样数量的汉字和同样数量的英文像素长度是不一样的&#xff0c;当我们限定固定长度后&#xff0c;在界面上的排版不够美观 痛点2…

多个服务器共享同一个Redis Cluster集群,并且可以使用Redisson分布式锁

Redisson 是一个高级的 Redis 客户端&#xff0c;它支持多种分布式 Java 对象和服务。其中之一就是分布式锁&#xff08;RLock&#xff09;&#xff0c;它可以跨多个应用实例在多个服务器上使用同一个 Redis 集群&#xff0c;为这些实例提供锁服务。 当你在不同服务器上运行的…

jmeter常用配置元件介绍总结之函数助手

系列文章目录 1.windows、linux安装jmeter及设置中文显示 2.jmeter常用配置元件介绍总结之安装插件 3.jmeter常用配置元件介绍总结之取样器 jmeter常用配置元件介绍总结之函数助手 1.进入函数助手对话框2.常用函数的使用介绍2.1.RandomFromMultipleVars函数2.2.Random函数2.3.R…

发现了NitroShare的一个bug

NitroShare 是一个跨平台的局域网开源网络文件传输应用程序&#xff0c;它利用广播发现机制在本地网络中找到其他安装了 NitroShare 的设备&#xff0c;从而实现这些设备之间的文件和文件夹发送。 NitroShare 支持 Windows、macOS 和 Linux 操作系统。 NitroShare允许我们为…

【 ElementUI 组件Steps 步骤条使用新手详细教程】

本文介绍如何使用 ElementUI 组件库中的步骤条组件完成分步表单设计。 效果图&#xff1a; 基础用法​ 简单的步骤条。 设置 active 属性&#xff0c;接受一个 Number&#xff0c;表明步骤的 index&#xff0c;从 0 开始。 需要定宽的步骤条时&#xff0c;设置 space 属性即…

互联网技术净土?原生鸿蒙开启全新技术征程

鸿蒙生态与开发者的崭新机会 HarmonyOS NEXT承载着华为对未来操作系统的深刻理解&#xff0c;如今已发展为坚实的数字底座。它不仅在技术层面取得了全面突破&#xff0c;还在中国操作系统市场中站稳了脚跟。 当前&#xff0c;HarmonyOS NEXT的代码行数已超过1.1亿&#xff0c…

[linux驱动开发--API框架]--platform、gpio、pinctrl

1. 结构体定义和实例化 // 这个结构体样式并不固定&#xff0c;按需增减成员&#xff0c;可以参考内核的其他驱动代码 struct leddev_dev{dev_t devid; /* 设备号*/struct cdev cdev; /* cdev*/struct class *class; /* 类*/struct device *d…

从书本到代码:人工智能如何改变教育游戏规则?

内容概要 随着时代的发展&#xff0c;人工智能在教育领域展现出前所未有的潜力&#xff0c;成为推动教育改革的重要力量。它不仅仅是一种技术工具&#xff0c;更是一种变革的催化剂&#xff0c;促使传统教育模式必须进行自我反思和更新。通过利用智能算法&#xff0c;教育者可…

发布一个npm组件库包

Webpack 配置 (webpack.config.js) const path require(path); const MiniCssExtractPlugin require(mini-css-extract-plugin); const CssMinimizerPlugin require(css-minimizer-webpack-plugin); const TerserPlugin require(terser-webpack-plugin);module.exports {…

C#语言:现代软件开发的核心工具

在当今快速发展的软件行业&#xff0c;C#&#xff08;发音为“C sharp”&#xff09;已成为开发人员广泛采用的一种编程语言。它由微软公司开发&#xff0c;旨在提供强大的功能、简洁的语法和广泛的适用性。自2000年首次发布以来&#xff0c;C#已成为构建各种类型应用程序的理想…

若Git子模块的远端地址发生了变化本地应该怎么调整

文章目录 前言git submodule 相关命令解决方案怎么保存子模块的版本呢总结 前言 这个问题复杂在既有Git又有子模块&#xff0c;本身Git的门槛就稍微高一点&#xff0c;再加上子模块的运用&#xff0c;一旦出现这种远端地址发生修改的情况会让人有些懵&#xff0c;不知道怎么处…

长视频为什么在广告市场上节节败退?

作者&#xff1a;刀客doc 在广告市场&#xff0c;长视频网站的吸引力在减小&#xff0c;这是不争的事实。不过最近我发现&#xff0c;这一趋势还在加剧。 近期&#xff0c;一份QuestMobile的数据预测了互联网各类媒介的市场份额。其中5年来&#xff0c;在线视频广告的份额年年…

Kubernetes-编排工具篇-01-Kustomize与Helm对比

Kustomize与Helm对比 0、前言 K8s 是一个开源容器编排平台&#xff0c;可自动执行容器化应用程序的部署、扩展和管理。近年来&#xff0c;K8s 已成为采用云原生架构和容器化技术的组织的标准。 但是由于K8s的复杂性&#xff0c;所以很多公司以及开源组织都在开发相关的工具来…

量子电路的实现 基于ibm的qiskit

量子计算的物理实现 量子计算的实现有几种方式&#xff0c;最常用的就是超导量子计算机&#xff0c;它的量子处理器是用超导传输量子比特构建的&#xff0c;它是由一个约瑟夫森结和一个并联的电容器组成的电路。约瑟夫森结是一种非线性电感&#xff0c;由两层重叠的超导…

【AIGC】如何通过ChatGPT轻松制作个性化GPTs应用

创建个性化的GPTs应用是一个涉及技术、设计和用户体验的过程。以下是详细步骤&#xff1a; ###1.确定应用目标和用户群体 在开始之前&#xff0c;你需要明确你的应用的目标和目标用户。这将帮助你在设计、开发和个性化方面做出相应的决策。例如&#xff0c;如果你的应用是为了…

cmake中execute_process详解

execute_process 是 CMake 中一个非常强大的命令&#xff0c;用于在构建过程中执行外部程序或脚本。它提供了丰富的选项来控制执行过程&#xff0c;并可以捕获输出、错误和返回码。以下是 execute_process 的详细解析&#xff1a; 基本语法 execute_process(COMMAND <comm…

141/142题环形链表

本题返回环入口的位置。使用快慢指针&#xff0c;快指针每次移动两个&#xff0c;慢指针每次移动一个。设前一段距离是a,进入环内到slow和fast相遇的地点距离是b&#xff0c;环内剩下的距离是c&#xff0c;如图所示。 环的长度是bc 慢指针移动距离是ab 快指针移动距离是abk(bc…

Linux-2

声明&#xff1a;学习视频来自b站up主 泷羽sec&#xff0c;如涉及侵权马上删除文章 感谢泷羽sec 团队的教学 视频地址&#xff1a;linux基础之病毒编写&#xff08;完结&#xff09;_哔哩哔哩_bilibili 一、Linux目录介绍 /bin&#xff1a;二进制可执行命令 /etc&#xff1a;…

快速入门Zookeeper

Zookeeper ZooKeeper作为一个强大的开源分布式协调服务&#xff0c;扮演着分布式系统中至关重要的角色。它提供了一个中心化的服务&#xff0c;用于维护配置信息、命名、提供分布式同步以及提供组服务等。通过其高性能和可靠的特性&#xff0c;ZooKeeper能够确保在复杂的分布式…

SpringBoot环境下的共享汽车管理策略

3系统分析 3.1可行性分析 通过对本共享汽车管理系统实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本共享汽车管理系统采用SSM框架&#xff0c;JAVA作为开发语…