Master Dynamic Data Permissions in Java with easy-data-scope
This tutorial walks you through building a Spring Boot project that uses the easy-data-scope library to inject dynamic SQL for fine‑grained data permissions, covering database setup, Maven dependencies, core annotations, custom rule implementation, and practical query examples.
Introduction
easy-data-scope is a data‑permission project that injects SQL dynamically. It supports MyBatis, MyBatis‑plus, and MyBatis‑flex, and works with simple annotations without complex configuration.
Basic Project Setup
1. Database
A simple user table is created to demonstrate various data‑permission scenarios.
Only view records with id = 1
Only view records with age = 111
Only view records with age = 222
View records with age = 111 or 222
2. Import Basic Dependencies (MyBatis‑plus, MyBatis XML)
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version>
</dependency>
</dependencies>3. Core Dependency
<dependency>
<groupId>cn.zlinchuan</groupId>
<artifactId>ds-mybatis</artifactId>
<version>1.0.1</version>
</dependency>4. Main Class
@SpringBootApplication
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class);
}
}5. Omitted Mapper and Service
Implementation details are omitted for brevity.
6. application.yml
server:
port: 8001
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/yourdb
username: youruser
password: yourpass
mybatis:
mapper-locations: classpath:mapper/*.xml
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImplUsing easy-data-scope
Implement the core interface DataScopeFindRule and let Spring manage it.
The library intercepts methods annotated with @DataScope and retrieves DataScopeInfo objects via the find() method.
DataScopeInfo Introduction
easy-data-scopebuilds SQL based on the list of DataScopeInfo returned by find().
@DataScope Introduction
Place the annotation on methods that require data‑permission filtering.
DataScope Annotation Attributes
public @interface DataScope {
/** Keys used to fetch permission entities */
String[] keys();
/** Template for building SQL when multiple keys are present */
String template() default "";
/** Whether to merge permissions with the same column/operator */
boolean merge() default false;
/** Logical connector (WHERE, AND, OR, etc.) */
String logical() default SqlConsts.AND;
/** Whether to use the data‑scope flag placeholder */
boolean flag() default false;
}Implementing DataScopeFindRule
@Override
public List<DataScopeInfo> find(String[] key) {
UserSessionInfo userSession = UserSessionContext.getUserSession();
if (userSession != null) {
QueryWrapper<AuthDatascopeEntity> qw = new QueryWrapper<>();
qw.in("id", userSession.getDataScopeIds());
qw.in("datascope_key", key);
List<AuthDatascopeEntity> list = authDataSocpeMapper.selectList(qw);
List<DataScopeInfo> infos = new ArrayList<>(list.size());
for (AuthDatascopeEntity e : list) {
DataScopeInfo i = new DataScopeInfo();
i.setKey(e.getDatascopeKey());
i.setOperator(e.getDatascopeOpName());
i.setTableName(e.getDatascopeTbName());
i.setColumnName(e.getDatascopeColName());
i.setSql(e.getDatascopeSql());
i.setValue(e.getDatascopeValue());
i.setSort(e.getDatascopeSort());
infos.add(i);
}
return infos;
}
return Collections.emptyList();
}Creating the Data Permission Table
CREATE TABLE auth_datascope (
id INT AUTO_INCREMENT PRIMARY KEY COMMENT '编号',
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 '数据权限表';Permission Scenarios
1. Only view records with id = 1
@DataScope(keys = "USER_LIST_ID", logical = SqlConsts.WHERE)
public List<UserEntity> getAll() {
return userMapper.selectList(null);
}Generated SQL:
SELECT id, username, age FROM user WHERE (user.id = 1)2. Only view records with age = 111
@DataScope(keys = "USER_LIST_AGE111", logical = SqlConsts.WHERE)
public List<UserEntity> getAll2() {
return userMapper.selectList(null);
} SELECT id, username, age FROM user WHERE (user.age = 111)3. Only view records with age = 222
@DataScope(keys = "USER_LIST_AGE222", logical = SqlConsts.WHERE)
public List<UserEntity> getAll3() {
return userMapper.selectList(null);
} SELECT id, username, age FROM user WHERE (user.age = 222)4. View records with age = 111 OR 222 (merge)
@DataScope(keys = {"USER_LIST_AGE111", "USER_LIST_AGE222"}, merge = true, logical = SqlConsts.WHERE)
public List<UserEntity> getAll4() {
return userMapper.selectList(null);
} SELECT id, username, age FROM user WHERE (user.age IN (111, 222))Advanced Operations
@DataScope.flag
@DataScope(keys = {"USER_LIST_AGE111", "USER_LIST_AGE222"}, merge = true, flag = true)
List<UserEntity> getAll5();Mapper XML uses the placeholder {{_DATA_SCOPE_FLAG}} which must not be altered.
@DataScope.template
@DataScope(keys = {"USER_LIST_AGE111", "USER_LIST_AGE222"}, flag = true, template = "{{USER_LIST_AGE111}} OR {{USER_LIST_AGE222}}")
List<UserEntity> getAll6(); SELECT * FROM (SELECT * FROM user WHERE user.age = 111 OR user.age = 222) t WHERE 1 = 1Project Source
https://github.com/zoulinchuan/easy-data-scope
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Architect's Tech Stack
Java backend, microservices, distributed systems, containerized programming, and more.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
