【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网络用来共享…...
React 第五十五节 Router 中 useAsyncError的使用详解
前言 useAsyncError 是 React Router v6.4 引入的一个钩子,用于处理异步操作(如数据加载)中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误:捕获在 loader 或 action 中发生的异步错误替…...

超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...

51c自动驾驶~合集58
我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留,CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制(CCA-Attention),…...
Java 语言特性(面试系列1)
一、面向对象编程 1. 封装(Encapsulation) 定义:将数据(属性)和操作数据的方法绑定在一起,通过访问控制符(private、protected、public)隐藏内部实现细节。示例: public …...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

基于ASP.NET+ SQL Server实现(Web)医院信息管理系统
医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上,开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识,在 vs 2017 平台上,进行 ASP.NET 应用程序和简易网站的开发;初步熟悉开发一…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...

前端导出带有合并单元格的列表
// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)
Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败,具体原因是客户端发送了密码认证请求,但Redis服务器未设置密码 1.为Redis设置密码(匹配客户端配置) 步骤: 1).修…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比
在机器学习的回归分析中,损失函数的选择对模型性能具有决定性影响。均方误差(MSE)作为经典的损失函数,在处理干净数据时表现优异,但在面对包含异常值的噪声数据时,其对大误差的二次惩罚机制往往导致模型参数…...