diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/DataScopeType.java b/ruoyi-common/src/main/java/com/ruoyi/common/enums/DataScopeType.java index 3d182709b..3b743e2a7 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/enums/DataScopeType.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/enums/DataScopeType.java @@ -23,22 +23,22 @@ public enum DataScopeType { /** * 自定数据权限 */ - DATA_SCOPE_CUSTOM("2", " OR #{#deptName} IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = #{#roleId} ) "), + DATA_SCOPE_CUSTOM("2", " #{#deptName} IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = #{#roleId} ) "), /** * 部门数据权限 */ - DATA_SCOPE_DEPT("3", " OR #{#deptName} = #{#deptId} "), + DATA_SCOPE_DEPT("3", " #{#deptName} = #{#deptId} "), /** * 部门及以下数据权限 */ - DATA_SCOPE_DEPT_AND_CHILD("4", " OR #{#deptName} IN ( SELECT dept_id FROM sys_dept WHERE dept_id = #{#deptId} OR find_in_set( #{#deptId} , ancestors ) )"), + DATA_SCOPE_DEPT_AND_CHILD("4", " #{#deptName} IN ( SELECT dept_id FROM sys_dept WHERE dept_id = #{#deptId} OR find_in_set( #{#deptId} , ancestors ) )"), /** * 仅本人数据权限 */ - DATA_SCOPE_SELF("5", " OR #{#userName?:1} = #{#userId?:0} "); + DATA_SCOPE_SELF("5", " #{#userName?:1} = #{#userId?:0} "); private final String code; diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/mapper/TestDemoMapper.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/mapper/TestDemoMapper.java index fd5b84951..7a3cb62d6 100644 --- a/ruoyi-demo/src/main/java/com/ruoyi/demo/mapper/TestDemoMapper.java +++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/mapper/TestDemoMapper.java @@ -11,6 +11,8 @@ import com.ruoyi.demo.domain.TestDemo; import com.ruoyi.demo.domain.vo.TestDemoVo; import org.apache.ibatis.annotations.Param; +import java.io.Serializable; +import java.util.Collection; import java.util.List; /** @@ -40,4 +42,18 @@ public interface TestDemoMapper extends BaseMapperPlus { @DataColumn(key = "userName", value = "user_id") }) List selectList(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + @Override + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "user_id") + }) + int updateById(@Param(Constants.ENTITY) TestDemo entity); + + @Override + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "user_id") + }) + int deleteBatchIds(@Param(Constants.COLLECTION) Collection idList); } diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/mapper/TestTreeMapper.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/mapper/TestTreeMapper.java index 590b50d0d..388095009 100644 --- a/ruoyi-demo/src/main/java/com/ruoyi/demo/mapper/TestTreeMapper.java +++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/mapper/TestTreeMapper.java @@ -8,6 +8,8 @@ import com.ruoyi.common.core.mybatisplus.core.BaseMapperPlus; import com.ruoyi.demo.domain.TestTree; import org.apache.ibatis.annotations.Param; +import java.io.Serializable; +import java.util.Collection; import java.util.List; /** @@ -24,4 +26,18 @@ public interface TestTreeMapper extends BaseMapperPlus { @DataColumn(key = "userName", value = "user_id") }) List selectList(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + @Override + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "user_id") + }) + int updateById(@Param(Constants.ENTITY) TestTree entity); + + @Override + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "user_id") + }) + int deleteBatchIds(@Param(Constants.COLLECTION) Collection idList); } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/Interceptor/PlusDataPermissionInterceptor.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/Interceptor/PlusDataPermissionInterceptor.java new file mode 100644 index 000000000..1c3d6e02a --- /dev/null +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/Interceptor/PlusDataPermissionInterceptor.java @@ -0,0 +1,96 @@ +package com.ruoyi.framework.Interceptor; + +import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper; +import com.baomidou.mybatisplus.core.toolkit.PluginUtils; +import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport; +import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor; +import com.ruoyi.framework.handler.PlusDataPermissionHandler; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.statement.delete.Delete; +import net.sf.jsqlparser.statement.select.PlainSelect; +import net.sf.jsqlparser.statement.select.Select; +import net.sf.jsqlparser.statement.select.SelectBody; +import net.sf.jsqlparser.statement.select.SetOperationList; +import net.sf.jsqlparser.statement.update.Update; +import org.apache.ibatis.executor.Executor; +import org.apache.ibatis.executor.statement.StatementHandler; +import org.apache.ibatis.mapping.BoundSql; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.mapping.SqlCommandType; +import org.apache.ibatis.session.ResultHandler; +import org.apache.ibatis.session.RowBounds; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.List; + +public class PlusDataPermissionInterceptor extends JsqlParserSupport implements InnerInterceptor { + + private final PlusDataPermissionHandler dataPermissionHandler = new PlusDataPermissionHandler(); + + @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(parserSingle(mpBs.sql(), ms.getId())); + } + + @Override + public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) { + PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh); + MappedStatement ms = mpSh.mappedStatement(); + SqlCommandType sct = ms.getSqlCommandType(); + if (sct == SqlCommandType.UPDATE || sct == SqlCommandType.DELETE) { + if (InterceptorIgnoreHelper.willIgnoreDataPermission(ms.getId())) { + return; + } + PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql(); + mpBs.sql(parserMulti(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 selectBodyList = setOperationList.getSelects(); + selectBodyList.forEach(s -> this.setWhere((PlainSelect) s, (String) obj)); + } + } + + @Override + protected void processUpdate(Update update, int index, String sql, Object obj) { + Expression sqlSegment = dataPermissionHandler.getSqlSegment(update.getWhere(), (String) obj, false); + if (null != sqlSegment) { + update.setWhere(sqlSegment); + } + } + + @Override + protected void processDelete(Delete delete, int index, String sql, Object obj) { + Expression sqlSegment = dataPermissionHandler.getSqlSegment(delete.getWhere(), (String) obj, false); + if (null != sqlSegment) { + delete.setWhere(sqlSegment); + } + } + + /** + * 设置 where 条件 + * + * @param plainSelect 查询对象 + * @param mappedStatementId 执行方法id + */ + protected void setWhere(PlainSelect plainSelect, String mappedStatementId) { + Expression sqlSegment = dataPermissionHandler.getSqlSegment(plainSelect.getWhere(), mappedStatementId, true); + if (null != sqlSegment) { + plainSelect.setWhere(sqlSegment); + } + } + +} + diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/MybatisPlusConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/MybatisPlusConfig.java index 539cc1d61..aeae4a31c 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/MybatisPlusConfig.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/MybatisPlusConfig.java @@ -6,12 +6,11 @@ import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector; import com.baomidou.mybatisplus.core.injector.ISqlInjector; import com.baomidou.mybatisplus.core.metadata.TableInfo; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; -import com.baomidou.mybatisplus.extension.plugins.inner.DataPermissionInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import com.ruoyi.common.core.mybatisplus.methods.InsertAll; +import com.ruoyi.framework.Interceptor.PlusDataPermissionInterceptor; import com.ruoyi.framework.handler.CreateAndUpdateMetaObjectHandler; -import com.ruoyi.framework.handler.PlusDataPermissionHandler; import org.mybatis.spring.annotation.MapperScan; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -42,12 +41,10 @@ public class MybatisPlusConfig { } /** - * 分页插件,自动识别数据库类型 + * 数据权限拦截器 */ - public DataPermissionInterceptor dataPermissionInterceptor() { - DataPermissionInterceptor dataPermissionInterceptor = new DataPermissionInterceptor(); - dataPermissionInterceptor.setDataPermissionHandler(new PlusDataPermissionHandler()); - return dataPermissionInterceptor; + public PlusDataPermissionInterceptor dataPermissionInterceptor() { + return new PlusDataPermissionInterceptor(); } /** diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/handler/PlusDataPermissionHandler.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/handler/PlusDataPermissionHandler.java index 4f811ca7f..0f791ae8f 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/handler/PlusDataPermissionHandler.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/handler/PlusDataPermissionHandler.java @@ -4,7 +4,6 @@ import cn.hutool.core.annotation.AnnotationUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ClassUtil; import cn.hutool.core.util.ObjectUtil; -import com.baomidou.mybatisplus.extension.plugins.handler.DataPermissionHandler; import com.ruoyi.common.annotation.DataColumn; import com.ruoyi.common.annotation.DataPermission; import com.ruoyi.common.core.domain.entity.SysRole; @@ -37,13 +36,12 @@ import java.util.stream.Collectors; * @author Lion Li */ @Slf4j -public class PlusDataPermissionHandler implements DataPermissionHandler { +public class PlusDataPermissionHandler { private final ExpressionParser parser = new SpelExpressionParser(); private final TemplateParserContext parserContext = new TemplateParserContext(); - @Override - public Expression getSqlSegment(Expression where, String mappedStatementId) { + public Expression getSqlSegment(Expression where, String mappedStatementId, boolean isSelect) { DataColumn[] dataColumns = findAnnotation(mappedStatementId); if (ArrayUtil.isEmpty(dataColumns)) { return where; @@ -53,7 +51,7 @@ public class PlusDataPermissionHandler implements DataPermissionHandler { if (StringUtils.isNull(currentUser) || currentUser.isAdmin()) { return where; } - String dataFilterSql = buildDataFilter(currentUser, dataColumns); + String dataFilterSql = buildDataFilter(currentUser, dataColumns, isSelect); if (StringUtils.isBlank(dataFilterSql)) { return where; } @@ -72,7 +70,7 @@ public class PlusDataPermissionHandler implements DataPermissionHandler { /** * 构造数据过滤sql */ - private String buildDataFilter(SysUser user, DataColumn[] dataColumns) { + private String buildDataFilter(SysUser user, DataColumn[] dataColumns, boolean isSelect) { StringBuilder sqlString = new StringBuilder(); EvaluationContext context = new StandardEvaluationContext(); @@ -93,6 +91,12 @@ public class PlusDataPermissionHandler implements DataPermissionHandler { if (type == DataScopeType.DATA_SCOPE_ALL) { return ""; } + // 不包含 key 变量 则不处理 + if (!StringUtils.contains(type.getSql(), "#" + dataColumn.key())) { + continue; + } + // 更新或删除需满足所有条件 + sqlString.append(isSelect ? " OR " : " AND "); // 解析sql模板并填充 String sql = parser.parseExpression(type.getSql(), parserContext).getValue(context, String.class); sqlString.append(sql); @@ -100,7 +104,7 @@ public class PlusDataPermissionHandler implements DataPermissionHandler { } if (StringUtils.isNotBlank(sqlString.toString())) { - return sqlString.substring(4); + return sqlString.substring(isSelect ? 4 : 5); } return ""; }