文章目录
-
-
- 一、前言
- 二、方案一 -- mybatis-mate-datascope
- 三、方案二 -- DataPermissionInterceptor数据权限插件
-
- 1、自定义数据权限插件`MyDataPermissionInterceptor`
- 2、自定义数据权限处理器
- 3、开启数据权限插件
- 四、方案三 -- 自定义数据权限拦截器
- 五、本文案例demo参考源码
-
一、前言
本文将基于mybatis-plus-boot-starter 3.4.3.1
来简单说下实现数据权限的几种解决方案
二、方案一 – mybatis-mate-datascope
- 官方文档: https://baomidou.com/pages/1864e1/#数据范围-数据权限
- 官方案例demo: https://gitee.com/baomidou/mybatis-mate-examples/tree/master/mybatis-mate-datascope
tips: 此方案为mp企业级模块功能,需个人授权证书方可使用
三、方案二 – DataPermissionInterceptor数据权限插件
com.baomidou.mybatisplus.extension.plugins.inner.DataPermissionInterceptor
1、自定义数据权限插件MyDataPermissionInterceptor
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@SuppressWarnings({"rawtypes"})
public class MyDataPermissionInterceptor extends JsqlParserSupport implements InnerInterceptor {
/**
* 数据权限处理器
*/
private MyDataPermissionHandler dataPermissionHandler;
@Override
public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
if (InterceptorIgnoreHelper.willIgnoreDataPermission(ms.getId())) {
return;
}
PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql);
mpBs.sql(this.parserSingle(mpBs.sql(), ms.getId()));
}
@Override
protected void processSelect(Select select, int index, String sql, Object obj) {
SelectBody selectBody = select.getSelectBody();
if (selectBody instanceof PlainSelect) {
this.setWhere((PlainSelect) selectBody, (String) obj);
} else if (selectBody instanceof SetOperationList) {
SetOperationList setOperationList = (SetOperationList) selectBody;
List<SelectBody> selectBodyList = setOperationList.getSelects();
selectBodyList.forEach(s -> this.setWhere((PlainSelect) s, (String) obj));
}
}
/**
* 设置 where 条件
*
* @param plainSelect 查询对象
* @param whereSegment 查询条件片段
*/
private void setWhere(PlainSelect plainSelect, String whereSegment) {
Expression sqlSegment = this.dataPermissionHandler.getSqlSegment(plainSelect, whereSegment);
if (null != sqlSegment) {
plainSelect.setWhere(sqlSegment);
}
}
}
2、自定义数据权限处理器
@Slf4j
public class MyDataPermissionHandler {
/**
* 获取数据权限 SQL 片段
*
* @param plainSelect 查询对象
* @param whereSegment 查询条件片段
* @return JSqlParser 条件表达式
*/
@SneakyThrows(Exception.class)
public Expression getSqlSegment(PlainSelect plainSelect, String whereSegment) {
// 待执行 SQL Where 条件表达式
Expression where = plainSelect.getWhere();
// 获取权限过滤相关信息 -- TODO 这里模拟拿到该操作用户的权限进行处理即可...
UserPermissionInfo userPermissionInfo = DataPermissionThreadLocal.get();
if (userPermissionInfo == null) {
return where;
}
Table fromItem = (Table) plainSelect.getFromItem();
// 有别名用别名,无别名用表名,防止字段冲突报错
Alias fromItemAlias = fromItem.getAlias();
String mainTableName = fromItemAlias == null ? fromItem.getName() : fromItemAlias.getName();
// 数据权限SQL -- create_by = userId
EqualsTo selfEqualsTo = new EqualsTo();
selfEqualsTo.setLeftExpression(new Column(mainTableName + ".create_by"));
selfEqualsTo.setRightExpression(new LongValue(userPermissionInfo.getUserId()));
return new AndExpression(where, selfEqualsTo);
}
}
3、开启数据权限插件
@Configuration
@EnableTransactionManagement
@MapperScan({"com.zhengqing.*.**.mapper*", "com.zhengqing.*.*.**.mapper*"})
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 添加数据权限插件
MyDataPermissionInterceptor dataPermissionInterceptor = new MyDataPermissionInterceptor();
// 添加自定义的数据权限处理器
dataPermissionInterceptor.setDataPermissionHandler(new MyDataPermissionHandler());
interceptor.addInnerInterceptor(dataPermissionInterceptor);
return interceptor;
}
}
四、方案三 – 自定义数据权限拦截器
tips: 此方案和方案二有些类似,相当于防着方案二自己造了一个demo
@Slf4j
@AllArgsConstructor
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
@Component
public class DataPermissionInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler statementHandler = PluginUtils.realTarget(invocation.getTarget());
MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
// 先判断是不是SELECT操作 不是直接过滤
MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
if (!SqlCommandType.SELECT.equals(mappedStatement.getSqlCommandType())) {
return invocation.proceed();
}
BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");
// 执行的SQL语句
String originalSql = boundSql.getSql();
// SQL语句的参数
Object parameterObject = boundSql.getParameterObject();
// TODO 这里对执行SQL进行自定义处理...
String finalSql = this.handleSql(originalSql);
System.err.println("数据权限处理过后的SQL: " + finalSql);
// 装载改写后的sql
metaObject.setValue("delegate.boundSql.sql", finalSql);
return invocation.proceed();
}
/**
* 改写SQL
* {@link com.baomidou.mybatisplus.extension.plugins.inner.DataPermissionInterceptor}
*
* @param originalSql 执行的SQL语句
* @return 处理后的SQL
* @author zhengqingya
* @date 2022/1/13 10:43
*/
private String handleSql(String originalSql) throws JSQLParserException {
CCJSqlParserManager parserManager = new CCJSqlParserManager();
Select select = (Select) parserManager.parse(new StringReader(originalSql));
SelectBody selectBody = select.getSelectBody();
if (selectBody instanceof PlainSelect) {
this.setWhere((PlainSelect) selectBody);
} else if (selectBody instanceof SetOperationList) {
SetOperationList setOperationList = (SetOperationList) selectBody;
List<SelectBody> selectBodyList = setOperationList.getSelects();
selectBodyList.forEach(s -> this.setWhere((PlainSelect) s));
}
return select.toString();
}
/**
* 设置 where 条件 -- 使用CCJSqlParser将原SQL进行解析并改写
*
* @param plainSelect 查询对象
*/
@SneakyThrows(Exception.class)
protected void setWhere(PlainSelect plainSelect) {
Table fromItem = (Table) plainSelect.getFromItem();
// 有别名用别名,无别名用表名,防止字段冲突报错
Alias fromItemAlias = fromItem.getAlias();
String mainTableName = fromItemAlias == null ? fromItem.getName() : fromItemAlias.getName();
// 构建子查询 -- 数据权限过滤SQL
String dataPermissionSql = mainTableName + ".create_by in ( 1, 2, 3 )";
if (plainSelect.getWhere() == null) {
plainSelect.setWhere(CCJSqlParserUtil.parseCondExpression(dataPermissionSql));
} else {
plainSelect.setWhere(new AndExpression(plainSelect.getWhere(), CCJSqlParserUtil.parseCondExpression(dataPermissionSql)));
}
}
/**
* 生成拦截对象的代理
*
* @param target 目标对象
* @return 代理对象
*/
@Override
public Object plugin(Object target) {
if (target instanceof StatementHandler) {
return Plugin.wrap(target, this);
}
return target;
}
/**
* mybatis配置的属性
*
* @param properties mybatis配置的属性
*/
@Override
public void setProperties(Properties properties) {
}
}
五、本文案例demo参考源码
https://gitee.com/zhengqingya/small-tools
今日分享语句:
天再高又怎样,踮起脚尖就更接近阳光。
相关文章
暂无评论...