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
usertable 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)
<code><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></code>3. Core Dependency
<code><dependency>
<groupId>cn.zlinchuan</groupId>
<artifactId>ds-mybatis</artifactId>
<version>1.0.1</version>
</dependency></code>4. Main Class
<code>@SpringBootApplication
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class);
}
}</code>5. Omitted Mapper and Service
Implementation details are omitted for brevity.
6. application.yml
<code>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.StdOutImpl</code>Using easy-data-scope
Implement the core interface
DataScopeFindRuleand let Spring manage it.
The library intercepts methods annotated with
@DataScopeand retrieves
DataScopeInfoobjects via the
find()method.
DataScopeInfo Introduction
easy-data-scopebuilds SQL based on the list of
DataScopeInforeturned by
find().
@DataScope Introduction
Place the annotation on methods that require data‑permission filtering.
DataScope Annotation Attributes
<code>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;
}</code>Implementing DataScopeFindRule
<code>@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();
}</code>Creating the Data Permission Table
<code>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 '数据权限表';</code>Permission Scenarios
1. Only view records with 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>2. Only view records with 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>3. Only view records with 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>4. View records with age = 111 OR 222 (merge)
<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>Advanced Operations
@DataScope.flag
<code>@DataScope(keys = {"USER_LIST_AGE111", "USER_LIST_AGE222"}, merge = true, flag = true)
List<UserEntity> getAll5();</code>Mapper XML uses the placeholder
{{_DATA_SCOPE_FLAG}}which must not be altered.
@DataScope.template
<code>@DataScope(keys = {"USER_LIST_AGE111", "USER_LIST_AGE222"}, flag = true, template = "{{USER_LIST_AGE111}} OR {{USER_LIST_AGE222}}")
List<UserEntity> getAll6();</code> <code>SELECT * FROM (SELECT * FROM user WHERE user.age = 111 OR user.age = 222) t WHERE 1 = 1</code>Project Source
https://github.com/zoulinchuan/easy-data-scope
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.