Backend Development 11 min read

Master Dynamic Data Permissions in Spring Boot with Easy-Data-Scope

This tutorial walks through setting up the easy-data-scope library in a Spring Boot project, configuring the database and dependencies, defining DataScopeInfo, using the @DataScope annotation, and demonstrating various permission scenarios such as filtering by ID, age, merging conditions, and custom templates.

macrozheng
macrozheng
macrozheng
Master Dynamic Data Permissions in Spring Boot with Easy-Data-Scope

Introduction

easy-data-scope

is a data‑permission project that injects SQL dynamically, supporting MyBatis, MyBatis‑plus, and MyBatis‑flex. It works via annotations without complex configuration.

Basic Project Setup

1. Database: a simple

user

table (see image).

Only view records with

id = 1

Only view records with

age = 111

Only view records with

age = 222

View records with

age = 111

or

age = 222

2. Add basic dependencies (MyBatis‑plus, MyBatis XML):

<code>&lt;dependencies&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
        &lt;artifactId&gt;spring-boot-starter&lt;/artifactId&gt;
        &lt;version&gt;2.2.1.RELEASE&lt;/version&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
        &lt;artifactId&gt;spring-boot-starter-test&lt;/artifactId&gt;
        &lt;version&gt;2.2.1.RELEASE&lt;/version&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;com.baomidou&lt;/groupId&gt;
        &lt;artifactId&gt;mybatis-plus-boot-starter&lt;/artifactId&gt;
        &lt;version&gt;3.3.0&lt;/version&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;com.mysql&lt;/groupId&gt;
        &lt;artifactId&gt;mysql-connector-j&lt;/artifactId&gt;
        &lt;version&gt;8.0.33&lt;/version&gt;
    &lt;/dependency&gt;
&lt;/dependencies&gt;</code>

3. Core dependency:

<code>&lt;dependency&gt;
    &lt;groupId&gt;cn.zlinchuan&lt;/groupId&gt;
    &lt;artifactId&gt;ds-mybatis&lt;/artifactId&gt;
    &lt;version&gt;1.0.1&lt;/version&gt;
&lt;/dependency&gt;</code>

4. Main class:

<code>@SpringBootApplication
public class Main {
    public static void main(String[] args) {
        SpringApplication.run(Main.class);
    }
}</code>

5.

application.yml

configuration:

<code>server:
  port: 8001
# DataSource Config
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: url
    username: name
    password: password
mybatis:
  mapper-locations: classpath:mapper/*.xml
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl</code>

Using easy-data-scope

Implement the core interface

DataScopeFindRule

and let Spring manage it.

DataScopeInfo

easy-data-scope

builds SQL based on the list of

DataScopeInfo

returned by

find()

.

@DataScope annotation

Place on methods that need data‑permission interception. Attributes include

keys

,

template

,

merge

,

logical

, and

flag

.

<code>public @interface DataScope {
    /** Keys used to retrieve DataScopeInfo */
    String[] keys();
    /** Template for building SQL when multiple keys are used */
    String template() default "";
    /** Whether to merge permissions with the same table/column */
    boolean merge() default false;
    /** Logical operator (WHERE, AND, OR, etc.) */
    String logical() default SqlConsts.AND;
    /** Whether to use the data‑scope flag placeholder */
    boolean flag() default false;
}</code>

Implementing DataScopeFindRule

<code>@Override
public List<DataScopeInfo> find(String[] key) {
    UserSessionInfo userSession = UserSessionContext.getUserSession();
    if (userSession != null) {
        QueryWrapper<AuthDatascopeEntity> idQueryWrapper = new QueryWrapper<>();
        idQueryWrapper.in("id", userSession.getDataScopeIds());
        idQueryWrapper.in("datascope_key", key);
        List<AuthDatascopeEntity> authDatascopes = authDataSocpeMapper.selectList(idQueryWrapper);
        List<DataScopeInfo> dataScopeInfos = new ArrayList<>(authDatascopes.size());
        for (AuthDatascopeEntity authDatascope : authDatascopes) {
            DataScopeInfo dataScopeInfo = new DataScopeInfo();
            dataScopeInfo.setKey(authDatascope.getDatascopeKey());
            dataScopeInfo.setOperator(authDatascope.getDatascopeOpName());
            dataScopeInfo.setTableName(authDatascope.getDatascopeTbName());
            dataScopeInfo.setColumnName(authDatascope.getDatascopeColName());
            dataScopeInfo.setSql(authDatascope.getDatascopeSql());
            dataScopeInfo.setValue(authDatascope.getDatascopeValue());
            dataScopeInfo.setSort(authDatascope.getDatascopeSort());
            dataScopeInfos.add(dataScopeInfo);
        }
        return dataScopeInfos;
    }
    return Collections.emptyList();
}</code>

Creating the data‑permission table

<code>CREATE TABLE auth_datascope (
    id int AUTO_INCREMENT PRIMARY KEY,
    datascope_key varchar(200) NULL COMMENT '数据权限标识',
    datascope_name varchar(200) NULL COMMENT '数据权限名称',
    datascope_tb_name varchar(500) NULL COMMENT '数据权限表别名',
    datascope_col_name varchar(500) NULL COMMENT '数据权限字段名',
    datascope_op_name varchar(10) NULL COMMENT '数据权限操作符',
    datascope_sql varchar(5000) NULL COMMENT '数据权限sql',
    datascope_value varchar(200) NULL COMMENT '数据权限值',
    datascope_sort int NULL COMMENT '数据权限排序',
    datascope_des varchar(500) NULL COMMENT '数据权限描述'
) COMMENT '数据权限表';</code>

Examples

Only

id = 1

:

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

Generated SQL:

<code>SELECT id,username,age FROM user WHERE ( user.id = 1 )</code>

Only

age = 111

:

<code>@DataScope(keys = "USER_LIST_AGE111", logical = SqlConsts.WHERE)
public List<UserEntity> getAll2() {
    return userMapper.selectList(null);
}</code>
<code>SELECT id,username,age FROM user WHERE ( user.age = 111 )</code>

Only

age = 222

:

<code>@DataScope(keys = "USER_LIST_AGE222", logical = SqlConsts.WHERE)
public List<UserEntity> getAll3() {
    return userMapper.selectList(null);
}</code>
<code>SELECT id,username,age FROM user WHERE ( user.age = 222 )</code>

Merge ages 111 and 222 (using

merge = true

):

<code>@DataScope(keys = {"USER_LIST_AGE111","USER_LIST_AGE222"}, merge = true, logical = SqlConsts.WHERE)
public List<UserEntity> getAll4() {
    return userMapper.selectList(null);
}</code>
<code>SELECT id,username,age FROM user WHERE ( user.age IN (111,222) )</code>

Using

flag

attribute in mapper XML:

<code>@DataScope(keys = {"USER_LIST_AGE111","USER_LIST_AGE222"}, merge = true, flag = true)
List<UserEntity> getAll5();

/* Mapper XML */
<select id="getAll5" resultType="cn.zlinchuan.entity.UserEntity">
    select * from (select * from user where {{_DATA_SCOPE_FLAG}}) t where 1 = 1
</select>
</code>

Using

template

attribute to customize SQL:

<code>@DataScope(keys = {"USER_LIST_AGE111","USER_LIST_AGE222"}, flag = true, template = "{{USER_LIST_AGE111}} OR {{USER_LIST_AGE222}}")
List<UserEntity> getAll6();

/* Mapper XML */
<select id="getAll6" resultType="cn.zlinchuan.entity.UserEntity">
    select * from (select * from user where {{_DATA_SCOPE_FLAG}}) t where 1 = 1
</select>
</code>

Project Source Code

GitHub repository: https://github.com/zoulinchuan/easy-data-scope

backendJavaSpring BootMyBatisAnnotationData Permission
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.