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.
Introduction
easy-data-scopeis 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
usertable (see image).
Only view records with
id = 1Only view records with
age = 111Only view records with
age = 222View records with
age = 111or
age = 2222. Add 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.
application.ymlconfiguration:
<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
DataScopeFindRuleand let Spring manage it.
DataScopeInfo
easy-data-scopebuilds SQL based on the list of
DataScopeInforeturned 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
flagattribute 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
templateattribute 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
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.
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.