【Spring Boot项目】根据用户的角色控制数据库访问权限
文章目录
- 简介
- 方法一
- 添加数据库依赖
- 配置数据库连接
- 创建用户角色表
- 创建Spring Data JPA实体和仓库
- 实现自定义的网关过滤器
- 配置网关过滤器
- 几个简单的测试API
- 方法二
- 创建数据库访问接口
- 实现数据库访问接口
- 创建用户角色判断逻辑
- 创建网关过滤器
- 配置网关过滤器
- 总结
简介
在一些特定的业务需求下,要求创建只读用户,但是由于一些查询请求使用的是POST方法,因此在网关层面配置只允许请求GET方法又无法满足。所以就想到了是否可以在 JDBC 层面控制,判断角色并且只允许执行 SELECT 类型的SQL语句。
在Spring Boot项目中,我们可以通过结合网关和JDBC来实现基于角色的数据库访问权限控制。具体来说,我们可以通过拦截用户请求并判断其角色,然后根据角色限制用户执行的SQL语句。
方法一
添加数据库依赖
在 pom.xml 文件中添加数据库相关依赖,如 spring-boot-starter-jdbc 和相应数据库驱动。
配置数据库连接
首先,我们需要配置数据库连接,以便能够与数据库进行交互。在 application.properties 或 application.yml 文件中添加以下配置信息:
spring:datasource:url: jdbc:mysql://localhost:3306/mydatabase?useSSL=falseusername: rootpassword: passworddriver-class-name: com.mysql.jdbc.Driver
这里使用了MySQL数据库作为示例,你可以根据实际情况配置相应的数据库连接信息。
创建用户角色表
为了实现角色的判断和数据库访问权限的控制,我们需要创建一个用户角色表,其中包含用户ID和角色字段。示例中,我们创建一个名为 user_roles 的表:
CREATE TABLE user_roles (id INT AUTO_INCREMENT PRIMARY KEY,user_id INT NOT NULL,role VARCHAR(20) NOT NULL
);
你可以根据实际需求扩展该表的字段,例如添加其他用户属性。
创建Spring Data JPA实体和仓库
接下来,我们创建与 user_roles 表对应的实体类和Spring Data JPA仓库接口。在 src/main/java 目录下创建一个 com.example.demo.entity 包,并在其中创建一个 UserRole 类:
import javax.persistence.*;@Entity
@Table(name = "user_roles")
public class UserRole {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;@Column(name = "user_id")private Long userId;private String role;// 省略构造函数、getter和setter方法
}
然后,在同一个包中创建一个 UserRoleRepository 接口,继承自 JpaRepository :
import org.springframework.data.jpa.repository.JpaRepository;public interface UserRoleRepository extends JpaRepository<UserRole, Long> {UserRole findByUserId(Long userId);
}
这样,我们就创建了实体类和仓库接口,用于操作用户角色数据。
实现自定义的网关过滤器
接下来,我们需要实现一个自定义的网关过滤器,用于拦截用户请求并进行角色判断。在 src/main/java 目录下创建一个 com.example.demo.filter 包,并在其中创建一个 DatabaseFilter 类:
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import reactor.core.publisher.Mono;@Component
public class DatabaseFilter extends AbstractGatewayFilterFactory<DatabaseFilter.Config> {private final UserRepository userRepository;private final UserRoleChecker userRoleChecker;public DatabaseFilter(UserRepository userRepository, UserRoleChecker userRoleChecker) {super(Config.class);this.userRepository = userRepository;this.userRoleChecker = userRoleChecker;}@Overridepublic GatewayFilter apply(Config config) {return (exchange, chain) -> {ServerHttpRequest request = exchange.getRequest();String userId = request.getHeaders().getFirst("UserId");if (!StringUtils.isEmpty(userId)) {Long userIdLong = Long.parseLong(userId);User user = userRepository.findById(userIdLong).orElse(null);if (user != null) {UserRole userRole = userRoleRepository.findByUserId(userIdLong);if (userRole != null) {if (config.getReadOnlyRoles().contains(userRole.getRole())) {// 只读角色,只允许执行SELECT查询语句String method = request.getMethodValue();if (!"GET".equals(method)) {exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);return exchange.getResponse().setComplete();}}}}}return chain.filter(exchange);};}public static class Config {private List<String> readOnlyRoles;public List<String> getReadOnlyRoles() {return readOnlyRoles;}public void setReadOnlyRoles(List<String> readOnlyRoles) {this.readOnlyRoles = readOnlyRoles;}}
}
在这个过滤器中,我们首先从请求头中获取用户ID,然后通过该ID查询用户角色。如果用户角色是只读角色(即在配置中指定的只读角色列表中),则判断请求方法是否为GET,如果不是GET方法,则返回HTTP状态码403,拒绝请求。如果用户角色不是只读角色,或者用户ID或角色不存在,将请求传递给下一个过滤器。
配置网关过滤器
最后,我们需要在网关配置文件中配置过滤器。在src/main/resources目录下的application.yml文件中,添加以下配置信息:
spring:cloud:gateway:routes:- id: jdbc-routeuri: http://localhost:8080predicates:- Path=/api/**filters:- DatabaseFilter=readOnlyRoles: [ROLE_READ_ONLY]
其中, readOnlyRoles 参数指定只读角色的名称,这里使用了 ROLE_READ_ONLY 作为示例。 /api/** 表示拦截以 /api/ 开头的请求,将其传递给 http://localhost:8080 的目标服务。
几个简单的测试API
这里提供了一个简单的示例代码,用于演示如何从JDBC入手,结合网关,根据用户角色限制执行的SQL语句。请注意,这只是一个简单的示例,你可以根据具体需求进行扩展和优化。
@RestController
@RequestMapping("/api")
public class UserController {@Autowiredprivate UserRepository userRepository;@GetMapping("/users")public List<User> getAllUsers() {return userRepository.findAll();}@GetMapping("/users/{id}")public User getUserById(@PathVariable Long id) {return userRepository.findById(id).orElse(null);}@PostMapping("/users")public User createUser(@RequestBody User user) {return userRepository.save(user);}@PutMapping("/users/{id}")public User updateUser(@PathVariable Long id, @RequestBody User user) {User existingUser = userRepository.findById(id).orElse(null);if (existingUser != null) {existingUser.setName(user.getName());existingUser.setEmail(user.getEmail());// ... 更新其他属性return userRepository.save(existingUser);}return null;}@DeleteMapping("/users/{id}")public void deleteUser(@PathVariable Long id) {userRepository.deleteById(id);}
}
在这个示例中,我们定义了几个用户管理的API接口,包括获取所有用户、根据ID获取用户、创建用户、更新用户和删除用户。根据之前配置的网关过滤器,在只读角色的情况下,只有GET请求方法能够执行成功,而其他方法将返回HTTP状态码403。
方法二
创建数据库访问接口
创建一个数据库访问接口,用于执行SQL查询。可以使用Spring JDBC或者使用ORM框架如MyBatis。
public interface UserRepository {List<User> findAll();
}
实现数据库访问接口
在实现类中使用 JdbcTemplate 或者其他数据库操作工具执行SQL语句。
@Repository
public class JdbcUserRepository implements UserRepository {private final JdbcTemplate jdbcTemplate;public JdbcUserRepository(JdbcTemplate jdbcTemplate) {this.jdbcTemplate = jdbcTemplate;}@Overridepublic List<User> findAll() {String sql = "SELECT * FROM users";return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(User.class));}
}
创建用户角色判断逻辑
创建一个用于判断用户角色的逻辑,可以使用Spring Security或者自定义注解来实现。
@Component
public class UserRoleChecker {public boolean isReadOnlyUser(User user) {// 根据用户角色判断是否只读用户return user.getRole().equals("READ_ONLY");}
}
创建网关过滤器
创建一个网关过滤器,用于在请求到达Controller之前进行权限判断,并阻止非只读用户执行非SELECT的SQL查询。
@Component
public class DatabaseFilter implements GlobalFilter, Ordered {private final UserRepository userRepository;private final UserRoleChecker userRoleChecker;public DatabaseFilter(UserRepository userRepository, UserRoleChecker userRoleChecker) {this.userRepository = userRepository;this.userRoleChecker = userRoleChecker;}@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {// 获取请求中的用户信息User user = getUserFromRequest(exchange.getRequest());// 判断用户角色是否只读用户boolean isReadOnlyUser = userRoleChecker.isReadOnlyUser(user);// 获取请求的SQL语句String sql = getSqlFromRequest(exchange.getRequest());// 如果是非只读用户且SQL语句不是SELECT,则拒绝请求if (!isReadOnlyUser && !sql.startsWith("SELECT")) {exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);return exchange.getResponse().setComplete();}return chain.filter(exchange);}@Overridepublic int getOrder() {return -1; // 设置过滤器优先级,确保在其他过滤器之前执行}private User getUserFromRequest(ServerHttpRequest request) {// 从请求中获取用户信息,可以从请求头、Cookie或者其他方式获取// 示例中直接返回一个固定的用户return new User("readonly", "READ_ONLY");}private String getSqlFromRequest(ServerHttpRequest request) {// 从请求中获取SQL语句,可以从请求参数、请求体或者其他方式获取。示例中直接返回一个固定的SQL语句。return "SELECT * FROM users";}}
配置网关过滤器
在Spring Boot的配置类中配置网关过滤器。
@Configuration
public class GatewayConfig {private final UserRepository userRepository;private final UserRoleChecker userRoleChecker;public GatewayConfig(UserRepository userRepository, UserRoleChecker userRoleChecker) {this.userRepository = userRepository;this.userRoleChecker = userRoleChecker;}@Beanpublic RouteLocator customRouteLocator(RouteLocatorBuilder builder) {return builder.routes().route("database", r -> r.path("/api/**").filters(f -> f.filter(new DatabaseFilter(userRepository, userRoleChecker))).uri("http://localhost:8080")).build();}
}
上述示例中,配置了一个名为"database"的路由,该路由会匹配所有以"/api/"开头的请求,并通过 DatabaseFilter 过滤器进行权限判断。如果用户角色是只读用户且SQL语句不是以"SELECT"开头,则拒绝请求。
总结
通过以上步骤,我们可以实现在Spring Boot项目中,根据用户的角色控制数据库访问权限。如果用户是只读人员角色,则只能执行SELECT的查询SQL,其他非SELECT的SQL语句会被拦截并拒绝执行。我们实现了从JDBC入手,结合网关,根据用户角色限制执行SQL语句的功能。你可以根据实际需求进行进一步的扩展和优化,例如在拦截器中添加更多的角色判断逻辑、使用自定义注解来标识只读方法等。
大家是否遇到类似问题,欢迎评论区讨论,如有错误之处,敬请留言!

相关文章:
【Spring Boot项目】根据用户的角色控制数据库访问权限
文章目录 简介方法一添加数据库依赖配置数据库连接创建用户角色表创建Spring Data JPA实体和仓库实现自定义的网关过滤器配置网关过滤器几个简单的测试API 方法二创建数据库访问接口实现数据库访问接口创建用户角色判断逻辑创建网关过滤器配置网关过滤器 总结 简介 在一些特定…...
EthernetIP 转MODBUS RTU协议网关连接FANUC机器人作为EthernetIP通信从站
远创智控YC-EIPM-RTU网关产品是一款高效的数据采集工具,它可以通过各种数据接口与工业领域的仪表、PLC、计量设备等产品连接,实时采集这些设备中的运行数据、状态数据等信息。采集到的数据经过整合和运算等操作后,可以被传输到其他设备或者云…...
如何注册微信小程序
如何注册微信小程序 前言 因为最近沉迷和朋友们一起下班去打麻将,他们推荐了一个计分的小程序,就不需要每局都转账或者用扑克牌记录了,但是这个小程序不仅打开有广告,各个页面都植入了广告,用起来十分不适。 于是我…...
移动App安全检测的必要性,app安全测试报告的编写注意事项
随着移动互联网的迅猛发展,移动App已经成为人们日常生活中不可或缺的一部分。然而,虽然App给我们带来了便利和乐趣,但也伴随着一些潜在的安全风险。黑客、病毒、恶意软件等威胁着用户的隐私和财产安全,因此进行安全检测就显得尤为…...
DVWA-JavaScript Attacks
JavaScript Attacks JavaScript Attack即JS攻击,攻击者可以利用JavaScript实施攻击。 Low 等级 核心源码,用的是dom语法这是在前端使用的和后端无关,然后获取属性为phrase的值然后来个rot13和MD5双重加密在复制给token属性。 <script&…...
算法通关村第二关|白银|链表反转拓展【持续更新】
1.指定区间反转 1.1 头插法:将区间内遍历到的结点插入到起始处之前。 public ListNode reverseBetween(ListNode head, int left, int right) {ListNode dummyNode new ListNode(-1);dummyNode.next head;ListNode pre dummyNode;// 将pre移动到区间的前一位&a…...
开发者职场“生存状态”大调研报告分析 - 第四版
听人劝、吃饱饭,奉劝各位小伙伴,不要订阅该文所属专栏。 作者:不渴望力量的哈士奇(哈哥),十余年工作经验, 跨域学习者,从事过全栈研发、产品经理等工作,现任研发部门 CTO 。荣誉:2022年度博客之星Top4、博客专家认证、全栈领域优质创作者、新星计划导师,“星荐官共赢计…...
代码与细节(一)
在用到 Java17的新特性 Unmodifiable Lists 时不知道你是否和我有同样的惊讶 为什么弄了这么多重载方法? 先说结论:为了性能。 其实一细想,都能想明白:varargs(可变参数) 的背后是数组的内存分配和初始化,相比正常的…...
AI绘画使用Stable Diffusion(SDXL)绘制中国古代神兽
一、引言 说到神奇异兽,脑海中首先就会跳出我国古代神话传说中的各种神兽。比如青龙、白虎、朱雀、玄武,再比如麒麟、凤凰、毕方、饕餮等等,这些都是大家耳熟能详的的神兽。 这些神兽不仅体现了人们丰富的创造力和想象力,更是我…...
老卫带你学---leetcode刷题(148. 排序链表)
148. 排序链表 问题: 给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。 示例 1:输入:head [4,2,1,3] 输出:[1,2,3,4]示例 2:输入:head [-1,5,3,4,0] 输出:[-1…...
21.1 stm32使用LTDC驱动LCD--配置说明
本文讲解如何配置LTDC驱动LCD的参数配置,以及CubeMx参数配置说明 本文使用的是淘宝买的一块带电容触摸的液晶显示屏:5寸TFT液晶显示屏高清800*480免驱40P通用RGBIPS全视角彩屏GT911 说实话,价格还是相对挺便宜的,值得入手…...
zabbix监控nginx的状态页面
zabbix监控nginx的状态页面 文章目录 zabbix监控nginx的状态页面1.环境说明2.所涉及到的知识点3.在nginx主机上安装zabbix_agent4.开启nginx状态显示页面5.进入zabbix的web页面配置主机,监控项,触发器5.1.添加主机5.2.创建监控项5.3.创建触发器 1.环境说…...
C语言初学者工具选择:vscode + MSYS2 + cmake 搭建 C环境
文章目录 前言1. MSYS2 安装1. 下载安装包2. 安装3. pacman 换清华大学源4. 安装 mingw-w64 toolchain 和 cmake ninja5. 将 toolchain 加入系统环境变量 2. 设置 vscode1. 必要的插件2. 一个简单的 vscode cmake 项目 最后C数据结构与算法CMake 前言 网上关于使用 vscode 配…...
【四:httpclient的使用】
目录 1、Demo案例2、请求一个带cookies的get请求3、请求一个带cookies的post请求案例一,案例二的properties的配置 1、Demo案例 public class MyHttpClient {Testpublic void test1() throws IOException {//用来存放我们的结果String result;HttpGet get new Htt…...
在innodb引擎中,count(*)、count(1)、count(主键)、count(字段)哪个性能最高?
在InnoDB引擎中,这四种计数值的效率高低取决于具体的数据库和数据表结构,无法一概而论哪个性能最高。不过,一般情况下可以按照以下顺序进行选择: count():统计所有行的数量。由于InnoDB引擎的行锁是锁住整行ÿ…...
华为OD 跳格子2(200分)【java】B卷
华为OD统一考试A卷B卷 新题库说明 你收到的链接上面会标注A卷还是B卷。目前大部分收到的都是B卷。 B卷对应20022部分考题以及新出的题目,A卷对应的是新出的题目。 我将持续更新最新题目 获取更多免费题目可前往夸克网盘下载,请点击此链接进入:…...
javascript/python 笔记: folium feature group自动切换
1 python部分 python部分只能是静态的结果 1.1 导入库 import folium import math 1.2 数据 cell_lst表示基站位置,location_lst表示 用户实际位置(均为伪数据) cell_lst[[1.341505, 103.682498],[1.342751, 103.679604],[1.341505, 10…...
Python中的元组
Python 元组 Python 的元组与列表类似,不同之处在于元组的元素不能修改。以下是关于Python元组的一些基本信息: 元组的使用:元组是一个不可变的序列类型,使用小括号 () 来定义。元组没有增加元素append、修改元素、删除元素pop的…...
在云计算环境中,如何利用 AI 改进云计算系统和数据库系统性能
文章目录 前言一、关于唐明洁教授二、AI for System2.1 面向分布式作业的人工智能2.1.1 现阶段企业云计算系统环境所遇到的普遍痛点2.1.2 云计算系统环境所遇到的普遍痛点的解决方案(一)Google Autopilot Eurosys 2021方案(Pod级别࿰…...
OpenP2P实现内网穿透远程办公
OpenP2P是一个开源、免费、轻量级的P2P共享网络。你的设备将组成一个私有P2P网络,里面的设备可以直接访问其它成员,或者通过其它成员转发数据间接访问。如果私有网络无法完成通信,将会到公有P2P网络寻找共享节点协助通信。 相比BT网络用来共享…...
网络六边形受到攻击
大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...
手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...
基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...
STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...
从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...
CSS | transition 和 transform的用处和区别
省流总结: transform用于变换/变形,transition是动画控制器 transform 用来对元素进行变形,常见的操作如下,它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...
