介绍
easy-data-scop
是一个通过动态注入SQL实现的数据权限项目。支持MyBatis、MyBatis-plus、MyBatis-flex。使用简单,无需设置各种复杂配置,仅仅通过注解便可实现效果功能。
基础项目搭建
1.数据库
这是一张简单的用户表,接下来我们将为这张表编写以下数据权限
- 仅看id为1的人
- 仅看年龄为111的人
- 仅看年龄为222的人
- 看年龄为111、222的人
2.导入依赖基础依赖 (使用MyBatis-plus、MyBatis XML演示)
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.核心依赖
xml
<dependency>
<groupId>cn.zlinchuan</groupId>
<artifactId>ds-mybatis</artifactId>
<version>1.0.1</version>
</dependency>
4.启动类
java
@SpringBootApplication
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class);
}
}
6.application.yml
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
5.省略编写Mapper、Service
6.测试
java
@Autowired
private UserService userService;
@Test
public void test() {
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介绍
可以编写在对应需要数据权限拦截的方法上
属性:
java
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
*/
boolean merge() default false;
/**
* 逻辑符
* 决定数据权限SQL拼接到当前执行的SQL中用的使用的是 WHERE还是AND还是OR..
* TODO 注意:在flag为true时此值将会失效
* @return
*/
String logical() default SqlConsts.AND;
/**
* 是否使用数据权限标记位标记位,true是 false否
* @return
*/
boolean flag() default false;
}
实现前文的数据权限
编写DataScopeFindRule
find 方法
java
@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();
}
创建数据权限表
sql
-- auto-generated definition
create table auth_datascope
(
id int auto_increment comment '编号'
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 '数据权限表';
1.只看Id为1的记录
将对应实体添加到库中,实现动态配置
编写Service
java
@DataScope(keys = "USER_LIST_ID", logical = SqlConsts.WHERE)
public List<UserEntity> getAll() {
return userMapper.selectList(null);
}
调用后得到结果
sql
SELECT id,username,age FROM user WHERE ( user.id = 1)
2.仅看年龄为111的人
java
@DataScope(keys = "USER_LIST_AGE111", logical = SqlConsts.WHERE)
public List<UserEntity> getAll2() {
return userMapper.selectList(null);
}
sql
sql
SELECT id,username,age FROM user WHERE ( user.age = 111)
2.仅看年龄为222的人
java
@DataScope(keys = "USER_LIST_AGE222", logical = SqlConsts.WHERE)
public List<UserEntity> getAll3() {
return userMapper.selectList(null);
}
sql
sql
SELECT id,username,age FROM user WHERE ( user.age = 222)
3.看年龄为111、222的人(merge属性)
其他的不用动,使用注解中的 merge 属性,在keys中将两个前两个key都加上
java
@DataScope(keys = {"USER_LIST_AGE111", "USER_LIST_AGE222"}, merge = true, logical = SqlConsts.WHERE)
public List<UserEntity> getAll4() {
return userMapper.selectList(null);
}
sql
sql
SELECT id,username,age FROM user WHERE ( user.age IN (111, 222))
更多操作
@DataScope.flag
Mapper.xml
java
@DataScope(keys = {"USER_LIST_AGE111", "USER_LIST_AGE222"}, merge = true, flag = true)
List<UserEntity> getAll5();
xml
<select id="getAll5" resultType="cn.zlinchuan.entity.UserEntity">
select * from (select * from user where {{_DATA_SCOPE_FLAG}}) t where 1 = 1
</select>
注意 {{_DATA_SCOPE_FLAG}}
为程序定义占位,不能修改
sql
sql
select * from (select * from user where user.age IN (111, 222)) t where 1 = 1
@DataScope.template
java
@DataScope(keys = {"USER_LIST_AGE111", "USER_LIST_AGE222"}, flag = true, template = "{{USER_LIST_AGE111}} OR {{USER_LIST_AGE222}}")
List<UserEntity> getAll6();
xml
<select id="getAll6" resultType="cn.zlinchuan.entity.UserEntity">
select * from (select * from user where {{_DATA_SCOPE_FLAG}}) t where 1 = 1
</select>
sql
sql
select * from (select * from user where user.age = 111 OR user.age = 222) t where 1 = 1