⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 网络 「网络」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言都将得到认真回复。甚至不知道如何读源码也可以请教噢。
  4. 新的源码解析文章实时收到通知。每周更新一篇左右。
  5. 认真的源码交流微信群。

介绍

easy-data-scop 是一个通过动态注入SQL实现的数据权限项目。支持MyBatis、MyBatis-plus、MyBatis-flex。使用简单,无需设置各种复杂配置,仅仅通过注解便可实现效果功能。

基础项目搭建

1.数据库

这是一张简单的用户表,接下来我们将为这张表编写以下数据权限

  • 仅看id为1的人
  • 仅看年龄为111的人
  • 仅看年龄为222的人
  • 看年龄为111、222的人

2.导入依赖基础依赖 (使用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.核心依赖

<dependency>
<groupId>cn.zlinchuan</groupId>
<artifactId>ds-mybatis</artifactId>
<version>1.0.1</version>
</dependency>

4.启动类

@SpringBootApplication
publicclassMain{
publicstaticvoidmain(String[] args){
SpringApplication.run(Main.class);
}
}

5.省略编写Mapper、Service

6.application.yml

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# XML映射文件路径
mybatis-plus:
configuration:
log-impl:org.apache.ibatis.logging.stdout.StdOutImpl

7.测试

@Autowired
private UserService userService;

@Test
publicvoidtest(){

userService.getAll().forEach(System.out::println);
}

到这里项目就已经搭建完成了

使用 easy-data-scope

实现核心接口DataScopeFindRule 并交由Spring管理

easy-data-scope` 会去代理 `@DataScope` 方法调用 `find()` 获取到 `DataScopeInfo

DataScopeInfo介绍

easy-data-scope 会根据 find() 方法返回的 DataScopeInfo 列表来构建SQL

@DataScope介绍

可以编写在对应需要数据权限拦截的方法上

属性:

public@interface DataScope {
/**
* 通过传递给DataScopeFindRule.find方法来获取指定的数据权限实体
* @return
*/
String[] keys();

/**
* 构建模板
* TODO 注意:当key为多个时此值生效
* key1 ==SQL==> table1.column1 = 1
* key2 ==SQL==> table2.column2 = 2
* 示例:template = "{key1} OR {key2}"
* 通过template生成后的SQL:table1.column1 = 1 OR table2.column2 = 2
* @return
*/
String template()default "";

/**
* 是否对数据权限进行自动合并
* 当操作符为 =、!= 时间如果TableName、ColumnName、操作符一样,并且使用的是 Value 形式将会对数据权限进行合并为 IN、NOT IN
* 示例:
* 权限1:=、table1、column1、Value1 >>> table1.column1 = Value1
* 权限2:=、table1、column1、Value2 >>> table1.column1 = Value2
* 最终合并 in table1、column1、“Value1, Value2" >>> table1.column1 in (Value1, Value2)
* @return
*/
booleanmerge()defaultfalse;

/**
* 逻辑符
* 决定数据权限SQL拼接到当前执行的SQL中用的使用的是 WHERE还是AND还是OR..
* TODO 注意:在flag为true时此值将会失效
* @return
*/
String logical()default SqlConsts.AND;

/**
* 是否使用数据权限标记位标记位,true是 false否
* @return
*/
booleanflag()defaultfalse;
}

实现前文的数据权限

编写DataScopeFindRule find 方法

@Override
public List<DataScopeInfo> find(String[] key){
// 模拟的用户登陆Session
UserSessionInfo userSession = UserSessionContext.getUserSession();
if (userSession != null) {
// 数据库中查询
QueryWrapper<AuthDatascopeEntity> idQueryWrapper = new QueryWrapper<>();
// 查询用户Session中保存用户有哪些数据权限
idQueryWrapper.in("id", userSession.getDataScopeIds());
idQueryWrapper.in("datascope_key", key);
List<AuthDatascopeEntity> authDatascopes = authDataSocpeMapper.selectList(idQueryWrapper);
// 构建出DataScopeInfo
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();
}

创建数据权限表

-- auto-generated definition
createtable auth_datascope
(
id int auto_increment comment'编号'
primary key ,
datascope_key varchar(200) nullcomment'数据权限标识' ,
datascope_name varchar(200) nullcomment'数据权限名称' ,
datascope_tb_name varchar(500) nullcomment'数据权限表别名' ,
datascope_col_name varchar(500) nullcomment'数据权限字段名' ,
datascope_op_name varchar(10) nullcomment'数据权限操作符' ,
datascope_sql varchar(5000) nullcomment'数据权限sql' ,
datascope_value varchar(200) nullcomment'数据权限值' ,
datascope_sort int nullcomment'数据权限排序' ,
datascope_des varchar(500) nullcomment'数据权限描述'
)
comment'数据权限表';

1.只看Id为1的记录

将对应实体添加到库中,实现动态配置

编写Service

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

调用后得到结果

SELECTid,username,age FROMuserWHERE ( user.id = 1)

2.仅看年龄为111的人

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

调用后得到结果

SELECT id,username,age FROMuserWHERE ( user.age = 111)

3.仅看年龄为222的人

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

调用后得到结果

SELECT id,username,age FROMuserWHERE ( user.age = 222)

4.看年龄为111、222的人(merge属性)

其他的不用动,使用注解中的 merge 属性,在keys中将两个前两个key都加上

@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 FROMuserWHERE ( user.age IN (111, 222))

更多操作

@DataScope.flag

Mapper.xml

@DataScope(keys = {"USER_LIST_AGE111", "USER_LIST_AGE222"}, merge = true, flag = true)
List<UserEntity> getAll5();
<selectid="getAll5"resultType="cn.zlinchuan.entity.UserEntity">
select * from (select * from user where {{_DATA_SCOPE_FLAG}}) t where 1 = 1
</select>

注意 为程序定义占位,不能修改

sql

select * from (select * fromuserwhere user.age IN (111, 222)) t where1 = 1

@DataScope.template

@DataScope(keys = {"USER_LIST_AGE111", "USER_LIST_AGE222"}, flag = true, template = "{{USER_LIST_AGE111}} OR {{USER_LIST_AGE222}}")
List<UserEntity> getAll6();
<selectid="getAll6"resultType="cn.zlinchuan.entity.UserEntity">
select * from (select * from user where {{_DATA_SCOPE_FLAG}}) t where 1 = 1
</select>

sql

select * from (select * fromuserwhere user.age = 111OR user.age = 222) t where1 = 1

项目源码地址

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

文章目录
  1. 1. 介绍
  2. 2. 基础项目搭建
    1. 2.0.0.1. 1.数据库
    2. 2.0.0.2. 2.导入依赖基础依赖 (使用MyBatis-plus、MyBatis XML演示)
    3. 2.0.0.3. 3.核心依赖
    4. 2.0.0.4. 4.启动类
    5. 2.0.0.5. 5.省略编写Mapper、Service
    6. 2.0.0.6. 6.application.yml
    7. 2.0.0.7. 7.测试
  • 3. 使用 easy-data-scope
    1. 3.0.1. DataScopeInfo介绍
    2. 3.0.2. @DataScope介绍
  • 4. 实现前文的数据权限
    1. 4.0.1. 创建数据权限表
  • 5. 1.只看Id为1的记录
  • 6. 2.仅看年龄为111的人
  • 7. 3.仅看年龄为222的人
  • 8. 4.看年龄为111、222的人(merge属性)
  • 9. 更多操作
    1. 9.0.1. @DataScope.flag
    2. 9.0.2. @DataScope.template
  • 10. 项目源码地址