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

news2025/1/17 21:32:19

文章目录

  • 简介
  • 方法一
    • 添加数据库依赖
    • 配置数据库连接
    • 创建用户角色表
    • 创建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=false
    username: root
    password: password
    driver-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;
    }
    
	@Override
    public 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-route
          uri: http://localhost:8080
          predicates:
            - 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 {

    @Autowired
    private 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;
    }

    @Override
    public 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;
    }

    @Override
    public 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);
    }

    @Override
    public 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;
    }

    @Bean
    public 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.coloradmin.cn/o/1107632.html

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

相关文章

0基础学习PyFlink——Map和Reduce函数处理单词统计

在很多讲解大数据的案例中&#xff0c;往往都会以一个单词统计例子来抛砖引玉。本文也不免俗&#xff0c;例子来源于PyFlink的《Table API Tutorial》&#xff0c;我们会通过几种方式统计不同的单词出现的个数&#xff0c;从而达到循序渐进的学习效果。 常规方法 # input.py …

《Python入门核心技术》专栏总目录

❤️ 专栏名称&#xff1a;《Python入门核心技术》 &#x1f338; 内容介绍&#xff1a;基础篇、进阶篇、Web篇、网络爬虫、数据分析、数据可视化、自动化等&#xff0c;适合零基础和进阶的同学。 &#x1f680; 订阅专栏&#xff1a;订阅后可阅读专栏内所有内容&#xff0c;专…

易点易动设备管理系统:提升生产企业设备保养效率的利器

在现代生产企业中&#xff0c;设备保养是确保生产线稳定运行和产品质量的关键环节。然而&#xff0c;传统的设备保养方式往往面临效率低下、数据不准确等问题&#xff0c;影响了生产效率和竞争力。随着科技的进步&#xff0c;易点易动设备管理系统应运而生&#xff0c;以其智能…

【Netty专题】【网络编程】从OSI、TCP/IP网络模型开始到BIO、NIO(Netty前置知识)

目录 前言前置知识一、计算机网络体系结构二、TCP/IP协议族2.1 简介*2.2 TCP/IP网络传输中的数据2.3 地址和端口号2.4 小总结 三、TCP/UDP特性3.1 TCP特性TCP 3次握手TCP 4次挥手TCP头部结构体 3.2 UDP特性 四、总结 课程内容一、网络通信编程基础知识1.1 什么是Socket1.2 长连…

kkFileView源码编译并发布详细教程

文章目录 概述为啥要自己进行源码编译我不懂Java代码&#xff0c;可以编译吗为什么写这篇教程 废话不多说&#xff0c;下面是详细操作教程安装JDK安装Git安装Maven编译kkFileView源码 kkFileView安装和使用编译后获得安装包&#xff0c;进行解压修改配置文件执行在线安装&#…

开源贡献难吗?

本文整理自字节跳动 Flink SQL 技术负责人李本超在 CommunityOverCode Asia 2023 上的 Keynote 演讲&#xff0c;李本超根据自己在开源社区的贡献经历&#xff0c;基于他在贡献开源社区过程中的一些小故事和思考&#xff0c;如何克服困难&#xff0c;在开源社区取得突破&#x…

DNS压测工具-dnsperf的安装和使用(centos)

系统调优 系统调优脚本&#xff0c;保存为sh文件&#xff0c;chmod提权后执行即可 #!/bin/sh #系统全局允许分配的最大文件句柄数&#xff1a; sysctl -w fs.file-max2097152 sysctl -w fs.nr_open2097152 echo 2097152 > /proc/sys/fs/nr_open #允许当前会话 / 进程打开文…

1.JDK的安装方法以及环境变量的配置

学习Java的第一步应该从配置环境开始&#xff0c;这篇博文介绍了在哪下载安装包以及如何在windows电脑中配置&#xff0c;希望大家看完后可以独立安装 ~ 文章目录 一、下载安装包二、 安装路径配置三、 环境变量配置四、 验证是否配置成功 一、下载安装包 安装包可以从官网下载…

第三方软件测评单位可为企业带来哪些收益?

随着信息科技的发展&#xff0c;软件市场竞争也越来越大&#xff0c;软件企业为了更好的专注于产品开发&#xff0c;以及保障软件质量&#xff0c;会将软件测试交由第三方软件测评单位进行。 第三方软件测评&#xff0c;顾名思义&#xff0c;是由独立的、与软件开发商无关的专业…

Unity中Shader的XRay透视效果

文章目录 前言一、模拟菲涅尔效果1、获取 V 向量2、获取 N 向量3、点积输出效果4、模拟出菲涅尔效果(中间暗&#xff0c;周围亮) 二、实现 &#xff38;Ray 效果1、使用半透明排序、修改混合模式、加点颜色2、增加分层效果&#xff08;使用 frac 函数&#xff0c;只取小数部分&…

CAPL如何实现27服务解锁

在文章《CANoe-如何实现27服务解锁》里,我们介绍了诊断控制台中如何实现27解锁,如果我想在CANoe中使用CAPL程序解锁的话,又要如何实现呢? CAPL脚本也是通过模拟手动操作来实现27解锁,所以步骤为: 发送10 03发送27 01接收67 01,获取seed值根据seed值和算法,计算出key值…

自5月以来,俄罗斯Sandworm黑客侵入了11家乌克兰电信公司

导语&#xff1a;据乌克兰计算机应急响应团队&#xff08;CERT-UA&#xff09;的最新报告称&#xff0c;自2023年5月至9月&#xff0c;俄罗斯政府支持的黑客组织Sandworm成功侵入了乌克兰的11家电信服务提供商。这一组织被认为与俄罗斯武装部队的GRU有关。 简介 根据乌克兰计算…

提高研发效率还得看Apipost

随着数字化转型的加速&#xff0c;API&#xff08;应用程序接口&#xff09;已经成为企业间沟通和数据交换的关键。而在API开发和管理过程中&#xff0c;API文档、调试、Mock和测试的协作显得尤为重要。Apipost正是这样一款一体化协作平台&#xff0c;旨在解决这些问题&#xf…

阿里内推强推的并发编程学习笔记,原理+实战+面试题,面面俱到!

并发编程 谈到并发编程&#xff0c;可能很多人都有过经验&#xff0c;甚至比我了解的更多。 那么并发与并行的区别又是什么&#xff1f; 并发编程是编程中的核心问题&#xff0c;实践中&#xff0c;当人们希望利用计算机处理一些现实世界问题&#xff0c;以及希望同时处理多…

使用DelayQueue的实现延时任务

1、背景 项目中经常会用到类似一些需要延迟执行的功能&#xff0c;比如缓存。java提供了DelayQueue来很轻松的实现这种功能。Delayed接口中的getDelay方法返回值小于等于0的时候&#xff0c;表示时间到达&#xff0c;可以从DelayQueue中通过take()方法取的到期的对象。到期对象…

电液比例负载控制变量泵PQ放大器

对驱动执行元件&#xff0c;仅供应所需最小限度的压力、流量的节能型泵控制系统。与专用功率放大器配合使用。流量和全截流压力按功率放大器的输入电流成比例地进行控制。在实际应用中&#xff0c;该控制系统与专用功率放大器配合使用&#xff0c;可以根据实际需求&#xff0c;…

Python学习基础笔记七十五——Python调用其他程序

Python经常被用来开发自动化程序。自动化程序往往需要调用其他的程序。 例如&#xff0c;我们可以代码中调用wget程序&#xff0c;而不是自己开发下载的代码。 这就是我们经常做的&#xff0c;在我们的Python程序中调佣其它程序&#xff0c;帮我们实现功能。 Python中调用外部…

python项目之网上商城的设计与实现(vue+django)

项目简介 网上商城的设计与实现实现了以下功能&#xff1a; 网上商城系统的开发设计按照系统应用功能划分分为了前端用户和后台用户。 通过网站平台实现首页商品信息的查看&#xff0c;同时可以结合需求进行在线的商品信息搜索&#xff0c;也可以按照系统首页提供的商品类别按…

什么是CSGO大行动,2023年CSGO大行动时间预测

什么是CSGO大行动&#xff0c;2023年CSGO大行动时间预测 什么是CSGO大行动&#xff0c;2023年CSGO大行动时间预测 那天群里在提大行动&#xff0c;不明所以的新同学在问&#xff0c;什么是大行动&#xff0c;是不是官方红锁大行动要来了&#xff1f;当然不是&#xff0c;别自己…

Windows/Linux系统ftp服务器搭建

文章目录 一、Windows系统ftp服务器搭建二、Linux系统ftp服务器搭建二、安装完成测试 一、Windows系统ftp服务器搭建 系统是2008r2&#xff0c;全图&#xff0c;按照图一步一步点就行了 找个有telnet的电脑测试一下端口&#xff0c;windows的ftp默认端口是21 返回…