【Spring Boot项目】根据用户的角色控制数据库访问权限

文章目录

  • 简介
  • 方法一
    • 添加数据库依赖
    • 配置数据库连接
    • 创建用户角色表
    • 创建Spring Data JPA实体和仓库
    • 实现自定义的网关过滤器
    • 配置网关过滤器
    • 几个简单的测试API
  • 方法二
    • 创建数据库访问接口
    • 实现数据库访问接口
    • 创建用户角色判断逻辑
    • 创建网关过滤器
    • 配置网关过滤器
  • 总结

简介

在一些特定的业务需求下,要求创建只读用户,但是由于一些查询请求使用的是POST方法,因此在网关层面配置只允许请求GET方法又无法满足。所以就想到了是否可以在 JDBC 层面控制,判断角色并且只允许执行 SELECT 类型的SQL语句。

在Spring Boot项目中,我们可以通过结合网关和JDBC来实现基于角色的数据库访问权限控制。具体来说,我们可以通过拦截用户请求并判断其角色,然后根据角色限制用户执行的SQL语句。

方法一

添加数据库依赖

pom.xml 文件中添加数据库相关依赖,如 spring-boot-starter-jdbc 和相应数据库驱动。

配置数据库连接

首先,我们需要配置数据库连接,以便能够与数据库进行交互。在 application.propertiesapplication.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语句的功能。你可以根据实际需求进行进一步的扩展和优化,例如在拦截器中添加更多的角色判断逻辑、使用自定义注解来标识只读方法等。

大家是否遇到类似问题,欢迎评论区讨论,如有错误之处,敬请留言!

在这里插入图片描述

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

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

相关文章

通讯网关软件027——利用CommGate X2OPCUA实现OPC UA访问MSSQL服务器

本文介绍利用CommGate X2OPCUA实现OPC UA访问MS SQL数据库。CommGate X2OPCUA是宁波科安网信开发的网关软件&#xff0c;软件可以登录到网信智汇(http://wangxinzhihui.com)下载。 【案例】如下图所示&#xff0c;实现上位机通过OPC UA来获取MS SQL数据库的数据。 【解决方案】…

Cobalt Strike

文章目录 简介CS与msf的不同工具使用安装插件 简介 Cobalt strike 是一款基于 java 的渗透测试神器&#xff0c;常被业界人称为 CS 神器。自3.0 以后已经不在使用 Metasploit 框架而作为一个独立的平台使用&#xff0c;分为客户端与服务端&#xff0c;服务端是一个&#xff0c;…

(2022|ECCV,文本图像视频,3D 邻域注意,3D 稀疏注意)NÜWA:神经视觉世界创建的视觉合成预训练

NWA: Visual Synthesis Pre-training for Neural visUalWorld creAtion 公众号&#xff1a;EDPJ&#xff08;添加 VX&#xff1a;CV_EDPJ 或直接进 Q 交流群&#xff1a;922230617 获取资料&#xff09; 目录 0. 摘要 1. 简介 2. 相关工作 2.1. 视觉自回归模型 2.2. 视觉…

Flutter 剪裁(Clip)

&#x1f525; ClipOval &#x1f525; 子组件为正方形时剪裁成内贴圆形&#xff1b;为矩形时&#xff0c;剪裁成内贴椭圆 裁剪纯色背景 ClipOval(child: Container(width: 300.w,height: 300.w,decoration: const BoxDecoration(color: Colors.red),),), 裁剪背景图片 裁剪前…

PositiveSSL的泛域名SSL证书

PositiveSSL是Sectigo旗下的一个子品牌&#xff0c;致力于为全球用户提供优质、高效的SSL证书服务。PositiveSSL以Sectigo强大的品牌影响力和全球网络为基础&#xff0c;秉承“安全、可靠、高效”的服务理念&#xff0c;为各类网站提供全面的SSL证书解决方案。今天就随SSL盾小编…

string类模拟实现(c++)(学习笔记)

string 1.构造函数1.1 不带参构造1.2 带参数的构造函数1.3 合并两个构造函数。 2. 析构函数3.拷贝构造函数4. 赋值运算符重载5. size()/capacity()6. 解引用[]8.iterator迭代器7.Print()8.> 8. push_back()&append()8.1 reserve() 9. 10.insert()10.1 任意位置插入一个字…

把微信好友不小心删了,有什么办法找回?

常见的重新加回微信好友有以下几种&#xff1a; ①通过微信群找回&#xff0c;看有无共同的群&#xff0c;重新将对方加回来 ②通过朋友圈的动态找回 ③如果是加不久的好友&#xff0c;可以在微信新的朋友功能里重新添加 ④通过共同好友&#xff0c;让朋友圈推荐好友名片找…

微信小程序--数字化会议OA系统之首页搭建

一、Flex弹性布局 布局的传统解决方案&#xff0c;基于盒状模型&#xff0c;依赖 display属性 position属性 float属性。它对于那些特殊布局非常不方便&#xff0c;比如&#xff0c;垂直居中就不容易实现。 2009年&#xff0c;W3C提出了一种新的方案—-Flex布局&#xff0c;可…

【10】基础知识:React - DOM的diffing算法

一、虚拟 DOM 中 key 的作用 react/vue 中的 key 有什么作用&#xff1f;key的内部原理是什么&#xff1f; 简单来说&#xff1a; key 是虚拟 DOM 对象的标识&#xff0c;在更新显示时 key 起着极其重要的作用&#xff0c;提高渲染效率&#xff0c;防止渲染错误。 详细的说…

如何通过Photoshop将视频转换成GIF图片

一、应用场景 1、将视频转有趣动图发朋友圈 2、写CSDN无法上传视频&#xff0c;而可以用GIF动图替代 3、其他 二、实现步骤 1、打开Photoshop APP 2、点击文件——导入——视频帧到图层 3、选择视频文件 4、配置视频信息&#xff0c;按照图片提示配置完毕之后点击确定&…

入门小白拥有服务器的建议

学习网络知识 当我们拥有了一台服务器以后,需要提前准备学习一些网络、服务器、互联网方便的知识, 以备在后续学习工作中使用。 建议的网络知识学习清单: 1. 网络基础知识:包括网络拓扑结构、协议、IP地址、子网掩码、网关等基础概念。 2. 网络安全:包括网络攻击类型、防…

Spring中注入的使用

目录 一、什么是注入&#xff08;Injection&#xff09; 1.1 为什么要注入 二、注入的基本使用 三、Spring注入原理分析 一、什么是注入&#xff08;Injection&#xff09; 注入就是通过Spring的配置文件&#xff0c;为所创建对象的成员变量进行赋值 1.1 为什么要注入 书接上…

idea dubge 详细

目录 一、概述 二、debug操作分析 1、打断点 2、运行debug模式 3、重新执行debug 4、让程序执行到下一次断点后暂停 5、让断点处的代码再加一行代码 6、停止debug程序 7、显示所有断点 8、添加断点运行的条件 9、屏蔽所有断点 10、把光标移到当前程序运行位置 11、单步跳过 12、…

wps/word 之 word中的两个表格 如何合并成为一个表格(已解决)

第一步&#xff1a;新建两个表格&#xff1a; 如何实现上面的两个表格合并呢&#xff1f; 分别选定每个表格&#xff0c;然后鼠标右键---》表格属性 在表格属性中的 表格---》选择 无文字环绕。 第二个表格按照同样的方法 设置 无文字环绕。 然后将中的文本行删去即可以了。选…

提升品牌形象:利用OLED透明拼接屏进行品牌展示

在当今数字化时代&#xff0c;OLED透明拼接屏作为一项引人注目的新兴技术&#xff0c;正逐渐改变着各行各业的显示方式。 OLED透明拼接屏技术 OLED透明拼接屏采用有机发光二极管&#xff08;OLED&#xff09;技术&#xff0c;能够提供卓越的显示效果。 与传统的液晶显示屏相比…

喜报!迅镭激光荣膺“江苏省智能制造领军服务机构”!

近日&#xff0c;“2023江苏省智能制造领军服务机构”名单揭晓&#xff0c;迅镭激光凭借在智能制造领域的强劲实力和突出的行业影响力位列其中&#xff0c;摘得该项殊荣。 近年来&#xff0c;智能制造正在成为全球传统工业和制造业转型升级的主要方向&#xff0c;越来越多的企业…

C++中的智能指针

智能指针是在 C 14 C14 C14中新引入的&#xff0c;所以在编译的时候最好加入 " − s t d c 14 " "-stdc14" "−stdc14"的编译选项。智能指针一共有两种&#xff0c;分别是 u n i q u e _ p t r unique\_ptr unique_ptr和 s h a r e d _ p t…

试着写几个opencv的程序

一、认识opencv OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一个开源计算机视觉库&#xff0c;旨在提供丰富的图像处理和计算机视觉功能&#xff0c;以帮助开发者构建视觉应用程序。OpenCV最初由英特尔开发&#xff0c;现在由社区维护和支持。它支持…

【UE4 反射系统】 UCLAS UFUNCTION UPROPERTY 宏简单解析 持续更新

目录 0 引言1 C如何实现反射机制1.1 使用代码生成工具实现反射机制 2 UE4的反射系统2.1 ****.generated.h头文件2.2 GENERATED_BODY()2.3 反射宏 UCLASS 等2.4 UHT和UBT 3 基本宏的使用3.1 UCLASS3.2 UFUNCTION3.3 UPROPERTY &#x1f64b;‍♂️ 作者&#xff1a;海码007&…

Axure RP医疗在线挂号问诊原型图医院APP原形模板

医疗在线挂号问诊Axure RP原型图医院APP原形模板&#xff0c;是一款原创的医疗类APP&#xff0c;设计尺寸采用iPhone13&#xff08;375*812px&#xff09;&#xff0c;原型图上加入了仿真手机壳&#xff0c;使得预览效果更加逼真。 本套原型图主要功能有医疗常识科普、医院挂号…