当前位置:首页 > 技术 > 正文内容

基于注解与动态SQL的SpringBoot数据权限实现方案

访客 技术 2026年9月27日 13

项目概述 easy-data-scope 是一个轻量级的数据权限控制框架,通过拦截 MyBatis 执行流程,在运行时动态注入 SQL 条件,实现灵活的数据访问控制。支持 MyBatis、MyBatis-Plus 和 MyBatis-Flex 等主流 ORM 框架。开发者仅需使用注解即可完成权限配置,无需修改原有业务逻辑。

环境搭建

  1. 数据库准备 以用户表为例:
CREATE TABLE `user` (
  `id` INT PRIMARY KEY,
  `username` VARCHAR(50),
  `age` INT
);

目标实现以下权限规则:

  • 只能查看 id 为 1 的记录
  • 只能查看 age 为 111 的用户
  • 只能查看 age 为 222 的用户
  • 可查看 age 为 111 或 222 的所有用户(合并条件)
  1. 添加基础依赖
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>2.7.0</version>
    </dependency>
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.2</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.30</version>
    </dependency>
</dependencies>
  1. 引入核心组件
<dependency>
    <groupId>cn.zlinchuan</groupId>
    <artifactId>ds-mybatis</artifactId>
    <version>1.0.1</version>
</dependency>
  1. 配置 application.yml
server:
  port: 8001

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test_db
    username: root
    password: 123456

mybatis-plus:
  mapper-locations: classpath:mapper/*.xml
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  1. 启动类
@SpringBootApplication
public class DataScopeApplication {
    public static void main(String[] args) {
        SpringApplication.run(DataScopeApplication.class, args);
    }
}

集成数据权限控制 需要实现 DataScopeFindRule 接口并注册为 Spring Bean,用于根据当前上下文生成数据范围信息。

@Component
public class CustomDataScopeRule implements DataScopeFindRule {

    @Autowired
    private AuthDatascopeMapper scopeMapper;

    @Override
    public List<DataScopeInfo> find(String[] keys) {
        LoginUser currentUser = SecurityContextHolder.getCurrentUser();
        if (currentUser == null || keys.length == 0) {
            return Collections.emptyList();
        }

        QueryWrapper<AuthDatascopeEntity> wrapper = new QueryWrapper<>();
        wrapper.in("datascope_key", keys);
        wrapper.in("role_id", currentUser.getRoleIds());
        List<AuthDatascopeEntity> records = scopeMapper.selectList(wrapper);

        return records.stream().map(entity -> {
            DataScopeInfo info = new DataScopeInfo();
            info.setKey(entity.getDatascopeKey());
            info.setTableName(entity.getDatascopeTbName());
            info.setColumnName(entity.getDatascopeColName());
            info.setOperator(entity.getDatascopeOpName());
            info.setValue(entity.getDatascopeValue());
            info.setSort(entity.getDatascopeSort());
            return info;
        }).collect(Collectors.toList());
    }
}

数据权限存储表结构

CREATE TABLE auth_datascope (
    id INT AUTO_INCREMENT PRIMARY KEY,
    datascope_key VARCHAR(200) COMMENT '权限标识',
    datascope_tb_name VARCHAR(500) COMMENT '表别名',
    datascope_col_name VARCHAR(500) COMMENT '字段名',
    datascope_op_name VARCHAR(10) COMMENT '操作符',
    datascope_value VARCHAR(200) COMMENT '值',
    role_id INT COMMENT '角色ID'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

注解使用详解 @DataScope 是核心注解,作用于方法上,触发权限拦截。

基本属性说明

  • keys: 权限键数组,传递给 find() 方法用于查询对应规则
  • logical: 连接符,默认为 AND,可选 WHERE、OR
  • merge: 是否自动合并相同字段的等值条件为 IN 查询
  • flag: 是否启用占位符模式,配合 XML 中的 {{_DATA_SCOPE_FLAG}} 使用
  • template: 自定义多个 key 的组合模板

实际应用场景演示

场景一:限制查看特定 ID 用户

@DataScope(keys = "USER_BY_ID", logical = SqlConsts.WHERE)
public List<UserEntity> fetchById() {
    return userMapper.selectList(null);
}

生成 SQL:

SELECT id, username, age FROM user WHERE (user.id = 1)

场景二:仅允许查看年龄为 111 的用户

@DataScope(keys = "USER_AGE_111", logical = SqlConsts.WHERE)
public List<UserEntity> listAge111() {
    return userMapper.selectList(null);
}

输出 SQL:

SELECT id, username, age FROM user WHERE (user.age = 111)

场景三:同时查看年龄为 111 和 222 的用户(启用合并)

@DataScope(keys = {"USER_AGE_111", "USER_AGE_222"}, merge = true, logical = SqlConsts.WHERE)
public List<UserEntity> listAges() {
    return userMapper.selectList(null);
}

最终 SQL 将被优化为 IN 查询:

SELECT id, username, age FROM user WHERE (user.age IN (111, 222))

场景四:使用 flag 占位符控制嵌套查询 Mapper 接口:

@DataScope(keys = {"USER_AGE_111", "USER_AGE_222"}, flag = true)
List<UserEntity> queryWithSubQuery();

XML 映射文件:

<select id="queryWithSubQuery" resultType="UserEntity">
    SELECT * FROM (
        SELECT * FROM user WHERE {{_DATA_SCOPE_FLAG}}
    ) t WHERE 1 = 1
</select>

执行效果:

SELECT * FROM (SELECT * FROM user WHERE user.age IN (111, 222)) t WHERE 1 = 1

场景五:自定义模板组合条件

@DataScope(
    keys = {"USER_AGE_111", "USER_AGE_222"},
    flag = true,
    template = "{{USER_AGE_111}} OR {{USER_AGE_222}}"
)
List<UserEntity> customTemplateQuery();

结合上述 XML,生成如下 SQL:

SELECT * FROM (SELECT * FROM user WHERE user.age = 111 OR user.age = 222) t WHERE 1 = 1

总结 该方案通过 AOP + SQL 动态改写的方式,实现了非侵入式的数据权限管理。结合数据库配置与注解驱动,使权限逻辑集中化、可视化,极大提升了系统的安全性和可维护性。

标签: springboot

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。