update [重大更新] 重写数据权限实现
This commit is contained in:
parent
79fc16eeb7
commit
aae3fe5305
@ -0,0 +1,25 @@
|
||||
package com.ruoyi.common.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 数据权限
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface DataColumn {
|
||||
|
||||
/**
|
||||
* 占位符关键字
|
||||
*/
|
||||
String key() default "deptName";
|
||||
|
||||
/**
|
||||
* 占位符替换值
|
||||
*/
|
||||
String value() default "dept_id";
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.ruoyi.common.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 数据权限组
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface DataPermission {
|
||||
|
||||
DataColumn[] value();
|
||||
|
||||
}
|
@ -6,11 +6,14 @@ import java.lang.annotation.*;
|
||||
* 数据权限过滤注解
|
||||
*
|
||||
* @author ruoyi
|
||||
* @deprecated 3.6.0 移除 {@link com.ruoyi.common.annotation.DataPermission}
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Deprecated
|
||||
public @interface DataScope {
|
||||
|
||||
/**
|
||||
* 部门表的别名
|
||||
*/
|
||||
@ -25,4 +28,5 @@ public @interface DataScope {
|
||||
* 是否过滤用户权限
|
||||
*/
|
||||
boolean isUser() default false;
|
||||
|
||||
}
|
||||
|
@ -162,7 +162,7 @@ public class SysUser extends BaseEntity {
|
||||
private Long[] postIds;
|
||||
|
||||
/**
|
||||
* 角色ID
|
||||
* 数据权限 当前角色ID
|
||||
*/
|
||||
@ApiModelProperty(value = "角色ID")
|
||||
@TableField(exist = false)
|
||||
|
@ -0,0 +1,66 @@
|
||||
package com.ruoyi.common.enums;
|
||||
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 数据权限类型
|
||||
*
|
||||
* 语法支持 spel 模板表达式
|
||||
*
|
||||
* 内置数据 user 当前用户 内容参考 SysUser
|
||||
* 如需扩展数据 需往 SysUser 内注入
|
||||
* 内置服务 sdss 系统数据权限服务 内容参考 SysDataScopeService
|
||||
* 如需扩展更多自定义服务 可以参考 sdss 自行编写
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum DataScopeType {
|
||||
|
||||
/**
|
||||
* 全部数据权限
|
||||
*/
|
||||
ALL("1", ""),
|
||||
|
||||
/**
|
||||
* 自定数据权限
|
||||
*/
|
||||
CUSTOM("2", " #{#deptName} IN ( #{@sdss.getRoleCustom( #user.roleId )} ) "),
|
||||
|
||||
/**
|
||||
* 部门数据权限
|
||||
*/
|
||||
DEPT("3", " #{#deptName} = #{#user.deptId} "),
|
||||
|
||||
/**
|
||||
* 部门及以下数据权限
|
||||
*/
|
||||
DEPT_AND_CHILD("4", " #{#deptName} IN ( #{@sdss.getDeptAndChild( #user.deptId )} )"),
|
||||
|
||||
/**
|
||||
* 仅本人数据权限
|
||||
*/
|
||||
SELF("5", " #{#userName?:1} = #{#user.userId} ");
|
||||
|
||||
private final String code;
|
||||
|
||||
/**
|
||||
* 语法 采用 spel 模板表达式
|
||||
*/
|
||||
private final String sql;
|
||||
|
||||
public static DataScopeType findCode(String code) {
|
||||
if (StringUtils.isBlank(code)) {
|
||||
return null;
|
||||
}
|
||||
for (DataScopeType type : values()) {
|
||||
if (type.getCode().equals(code)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,12 +1,20 @@
|
||||
package com.ruoyi.demo.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.common.annotation.DataColumn;
|
||||
import com.ruoyi.common.annotation.DataPermission;
|
||||
import com.ruoyi.common.core.mybatisplus.core.BaseMapperPlus;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 测试单表Mapper接口
|
||||
*
|
||||
@ -15,6 +23,37 @@ import org.apache.ibatis.annotations.Param;
|
||||
*/
|
||||
public interface TestDemoMapper extends BaseMapperPlus<TestDemo> {
|
||||
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "dept_id"),
|
||||
@DataColumn(key = "userName", value = "user_id")
|
||||
})
|
||||
Page<TestDemoVo> customPageList(@Param("page") Page<TestDemo> page, @Param("ew") Wrapper<TestDemo> wrapper);
|
||||
|
||||
@Override
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "dept_id"),
|
||||
@DataColumn(key = "userName", value = "user_id")
|
||||
})
|
||||
<P extends IPage<TestDemo>> P selectPage(P page, @Param(Constants.WRAPPER) Wrapper<TestDemo> queryWrapper);
|
||||
|
||||
@Override
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "dept_id"),
|
||||
@DataColumn(key = "userName", value = "user_id")
|
||||
})
|
||||
List<TestDemo> selectList(@Param(Constants.WRAPPER) Wrapper<TestDemo> 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<? extends Serializable> idList);
|
||||
}
|
||||
|
@ -1,7 +1,16 @@
|
||||
package com.ruoyi.demo.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import com.ruoyi.common.annotation.DataColumn;
|
||||
import com.ruoyi.common.annotation.DataPermission;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 测试树表Mapper接口
|
||||
@ -11,4 +20,24 @@ import com.ruoyi.demo.domain.TestTree;
|
||||
*/
|
||||
public interface TestTreeMapper extends BaseMapperPlus<TestTree> {
|
||||
|
||||
@Override
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "dept_id"),
|
||||
@DataColumn(key = "userName", value = "user_id")
|
||||
})
|
||||
List<TestTree> selectList(@Param(Constants.WRAPPER) Wrapper<TestTree> 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<? extends Serializable> idList);
|
||||
}
|
||||
|
@ -1,16 +1,15 @@
|
||||
package com.ruoyi.demo.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.ruoyi.common.core.domain.PageQuery;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.common.annotation.DataScope;
|
||||
import com.ruoyi.common.core.domain.PageQuery;
|
||||
import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
|
||||
import com.ruoyi.common.core.page.PagePlus;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.utils.PageUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.demo.domain.TestDemo;
|
||||
import com.ruoyi.demo.domain.bo.TestDemoBo;
|
||||
import com.ruoyi.demo.domain.vo.TestDemoVo;
|
||||
@ -36,7 +35,6 @@ public class TestDemoServiceImpl extends ServicePlusImpl<TestDemoMapper, TestDem
|
||||
return getVoById(id);
|
||||
}
|
||||
|
||||
@DataScope(isUser = true)
|
||||
@Override
|
||||
public TableDataInfo<TestDemoVo> queryPageList(TestDemoBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<TestDemo> lqw = buildQueryWrapper(bo);
|
||||
@ -47,7 +45,6 @@ public class TestDemoServiceImpl extends ServicePlusImpl<TestDemoMapper, TestDem
|
||||
/**
|
||||
* 自定义分页查询
|
||||
*/
|
||||
@DataScope(isUser = true)
|
||||
@Override
|
||||
public TableDataInfo<TestDemoVo> customPageList(TestDemoBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<TestDemo> lqw = buildQueryWrapper(bo);
|
||||
@ -55,7 +52,6 @@ public class TestDemoServiceImpl extends ServicePlusImpl<TestDemoMapper, TestDem
|
||||
return PageUtils.buildDataInfo(result);
|
||||
}
|
||||
|
||||
@DataScope(isUser = true)
|
||||
@Override
|
||||
public List<TestDemoVo> queryList(TestDemoBo bo) {
|
||||
return listVo(buildQueryWrapper(bo));
|
||||
@ -63,14 +59,11 @@ public class TestDemoServiceImpl extends ServicePlusImpl<TestDemoMapper, TestDem
|
||||
|
||||
private LambdaQueryWrapper<TestDemo> buildQueryWrapper(TestDemoBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
Object dataScope = params.get("dataScope");
|
||||
LambdaQueryWrapper<TestDemo> lqw = Wrappers.lambdaQuery();
|
||||
lqw.like(StringUtils.isNotBlank(bo.getTestKey()), TestDemo::getTestKey, bo.getTestKey());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getValue()), TestDemo::getValue, bo.getValue());
|
||||
lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
|
||||
TestDemo::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
|
||||
lqw.apply(dataScope != null && StringUtils.isNotBlank(dataScope.toString()),
|
||||
dataScope != null ? dataScope.toString() : null);
|
||||
return lqw;
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,6 @@ package com.ruoyi.demo.service.impl;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.ruoyi.common.annotation.DataScope;
|
||||
import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.demo.domain.TestTree;
|
||||
@ -33,7 +32,6 @@ public class TestTreeServiceImpl extends ServicePlusImpl<TestTreeMapper, TestTre
|
||||
}
|
||||
|
||||
// @DS("slave") // 切换从库查询
|
||||
@DataScope(isUser = true)
|
||||
@Override
|
||||
public List<TestTreeVo> queryList(TestTreeBo bo) {
|
||||
LambdaQueryWrapper<TestTree> lqw = buildQueryWrapper(bo);
|
||||
@ -42,13 +40,10 @@ public class TestTreeServiceImpl extends ServicePlusImpl<TestTreeMapper, TestTre
|
||||
|
||||
private LambdaQueryWrapper<TestTree> buildQueryWrapper(TestTreeBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
Object dataScope = params.get("dataScope");
|
||||
LambdaQueryWrapper<TestTree> lqw = Wrappers.lambdaQuery();
|
||||
lqw.like(StringUtils.isNotBlank(bo.getTreeName()), TestTree::getTreeName, bo.getTreeName());
|
||||
lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
|
||||
TestTree::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
|
||||
lqw.apply(dataScope != null && StringUtils.isNotBlank(dataScope.toString()),
|
||||
dataScope != null ? dataScope.toString() : null);
|
||||
return lqw;
|
||||
}
|
||||
|
||||
|
@ -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<SelectBody> 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,9 +18,11 @@ import org.springframework.stereotype.Component;
|
||||
* 数据过滤处理
|
||||
*
|
||||
* @author Lion Li
|
||||
* @deprecated 3.6.0 移除 {@link com.ruoyi.framework.handler.PlusDataPermissionHandler}
|
||||
*/
|
||||
@Aspect
|
||||
@Component
|
||||
@Deprecated
|
||||
public class DataScopeAspect {
|
||||
|
||||
/**
|
||||
|
@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
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 org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@ -30,6 +31,8 @@ public class MybatisPlusConfig {
|
||||
@Bean
|
||||
public MybatisPlusInterceptor mybatisPlusInterceptor() {
|
||||
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
|
||||
// 数据权限处理
|
||||
interceptor.addInnerInterceptor(dataPermissionInterceptor());
|
||||
// 分页插件
|
||||
interceptor.addInnerInterceptor(paginationInnerInterceptor());
|
||||
// 乐观锁插件
|
||||
@ -37,6 +40,13 @@ public class MybatisPlusConfig {
|
||||
return interceptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据权限拦截器
|
||||
*/
|
||||
public PlusDataPermissionInterceptor dataPermissionInterceptor() {
|
||||
return new PlusDataPermissionInterceptor();
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页插件,自动识别数据库类型
|
||||
*/
|
||||
|
@ -0,0 +1,133 @@
|
||||
package com.ruoyi.framework.handler;
|
||||
|
||||
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.ruoyi.common.annotation.DataColumn;
|
||||
import com.ruoyi.common.annotation.DataPermission;
|
||||
import com.ruoyi.common.core.domain.entity.SysRole;
|
||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||
import com.ruoyi.common.core.service.UserService;
|
||||
import com.ruoyi.common.enums.DataScopeType;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.common.utils.spring.SpringUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.sf.jsqlparser.JSQLParserException;
|
||||
import net.sf.jsqlparser.expression.Expression;
|
||||
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
|
||||
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
|
||||
import org.springframework.context.expression.BeanFactoryResolver;
|
||||
import org.springframework.expression.BeanResolver;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.expression.ParserContext;
|
||||
import org.springframework.expression.common.TemplateParserContext;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 数据权限过滤
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Slf4j
|
||||
public class PlusDataPermissionHandler {
|
||||
|
||||
private final ExpressionParser parser = new SpelExpressionParser();
|
||||
private final ParserContext parserContext = new TemplateParserContext();
|
||||
private final BeanResolver beanResolver = new BeanFactoryResolver(SpringUtils.getBeanFactory());
|
||||
|
||||
public Expression getSqlSegment(Expression where, String mappedStatementId, boolean isSelect) {
|
||||
DataColumn[] dataColumns = findAnnotation(mappedStatementId);
|
||||
if (ArrayUtil.isEmpty(dataColumns)) {
|
||||
return where;
|
||||
}
|
||||
SysUser currentUser = SpringUtils.getBean(UserService.class).selectUserById(SecurityUtils.getUserId());
|
||||
// 如果是超级管理员,则不过滤数据
|
||||
if (StringUtils.isNull(currentUser) || currentUser.isAdmin()) {
|
||||
return where;
|
||||
}
|
||||
String dataFilterSql = buildDataFilter(currentUser, dataColumns, isSelect);
|
||||
if (StringUtils.isBlank(dataFilterSql)) {
|
||||
return where;
|
||||
}
|
||||
try {
|
||||
Expression expression = CCJSqlParserUtil.parseExpression(dataFilterSql);
|
||||
if (ObjectUtil.isNotNull(where)) {
|
||||
return new AndExpression(where, expression);
|
||||
} else {
|
||||
return expression;
|
||||
}
|
||||
} catch (JSQLParserException e) {
|
||||
throw new ServiceException("数据权限解析异常 => " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造数据过滤sql
|
||||
*/
|
||||
private String buildDataFilter(SysUser user, DataColumn[] dataColumns, boolean isSelect) {
|
||||
StringBuilder sqlString = new StringBuilder();
|
||||
|
||||
StandardEvaluationContext context = new StandardEvaluationContext();
|
||||
context.setBeanResolver(beanResolver);
|
||||
context.setVariable("user", user);
|
||||
|
||||
for (DataColumn dataColumn : dataColumns) {
|
||||
// 设置注解变量 key 为表达式变量 value 为变量值
|
||||
context.setVariable(dataColumn.key(), dataColumn.value());
|
||||
for (SysRole role : user.getRoles()) {
|
||||
user.setRoleId(role.getRoleId());
|
||||
|
||||
// 获取角色权限泛型
|
||||
DataScopeType type = DataScopeType.findCode(role.getDataScope());
|
||||
if (ObjectUtil.isNull(type)) {
|
||||
throw new ServiceException("角色数据范围异常 => " + role.getDataScope());
|
||||
}
|
||||
// 全部数据权限直接返回
|
||||
if (type == DataScopeType.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);
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(sqlString.toString())) {
|
||||
return sqlString.substring(isSelect ? 4 : 5);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private DataColumn[] findAnnotation(String mappedStatementId) {
|
||||
StringBuilder sb = new StringBuilder(mappedStatementId);
|
||||
int index = sb.lastIndexOf(".");
|
||||
String clazzName = sb.substring(0, index);
|
||||
String methodName = sb.substring(index + 1, sb.length());
|
||||
Class<?> clazz = ClassUtil.loadClass(clazzName);
|
||||
List<Method> methods = Arrays.stream(ClassUtil.getDeclaredMethods(clazz))
|
||||
.filter(method -> method.getName().equals(methodName)).collect(Collectors.toList());
|
||||
DataPermission dataPermission;
|
||||
for (Method method : methods) {
|
||||
if (AnnotationUtil.hasAnnotation(method, DataPermission.class)) {
|
||||
dataPermission = AnnotationUtil.getAnnotation(method, DataPermission.class);
|
||||
return dataPermission.value();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
package com.ruoyi.system.mapper;
|
||||
|
||||
import com.ruoyi.common.annotation.DataColumn;
|
||||
import com.ruoyi.common.annotation.DataPermission;
|
||||
import com.ruoyi.common.core.domain.entity.SysDept;
|
||||
import com.ruoyi.common.core.mybatisplus.core.BaseMapperPlus;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
@ -19,6 +21,9 @@ public interface SysDeptMapper extends BaseMapperPlus<SysDept> {
|
||||
* @param dept 部门信息
|
||||
* @return 部门信息集合
|
||||
*/
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "d.dept_id")
|
||||
})
|
||||
List<SysDept> selectDeptList(SysDept dept);
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,8 @@
|
||||
package com.ruoyi.system.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.common.annotation.DataColumn;
|
||||
import com.ruoyi.common.annotation.DataPermission;
|
||||
import com.ruoyi.common.core.domain.entity.SysRole;
|
||||
import com.ruoyi.common.core.mybatisplus.core.BaseMapperPlus;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
@ -14,6 +16,9 @@ import java.util.List;
|
||||
*/
|
||||
public interface SysRoleMapper extends BaseMapperPlus<SysRole> {
|
||||
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "d.dept_id")
|
||||
})
|
||||
Page<SysRole> selectPageRoleList(@Param("page") Page<SysRole> page, @Param("role") SysRole role);
|
||||
|
||||
/**
|
||||
@ -22,6 +27,9 @@ public interface SysRoleMapper extends BaseMapperPlus<SysRole> {
|
||||
* @param role 角色信息
|
||||
* @return 角色数据集合信息
|
||||
*/
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "d.dept_id")
|
||||
})
|
||||
List<SysRole> selectRoleList(SysRole role);
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,8 @@
|
||||
package com.ruoyi.system.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.common.annotation.DataColumn;
|
||||
import com.ruoyi.common.annotation.DataPermission;
|
||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||
import com.ruoyi.common.core.mybatisplus.core.BaseMapperPlus;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
@ -14,6 +16,10 @@ import java.util.List;
|
||||
*/
|
||||
public interface SysUserMapper extends BaseMapperPlus<SysUser> {
|
||||
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "d.dept_id"),
|
||||
@DataColumn(key = "userName", value = "u.user_id")
|
||||
})
|
||||
Page<SysUser> selectPageUserList(@Param("page") Page<SysUser> page, @Param("user") SysUser user);
|
||||
|
||||
/**
|
||||
@ -22,6 +28,10 @@ public interface SysUserMapper extends BaseMapperPlus<SysUser> {
|
||||
* @param sysUser 用户信息
|
||||
* @return 用户信息集合信息
|
||||
*/
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "d.dept_id"),
|
||||
@DataColumn(key = "userName", value = "u.user_id")
|
||||
})
|
||||
List<SysUser> selectUserList(SysUser sysUser);
|
||||
|
||||
/**
|
||||
@ -30,6 +40,10 @@ public interface SysUserMapper extends BaseMapperPlus<SysUser> {
|
||||
* @param user 用户信息
|
||||
* @return 用户信息集合信息
|
||||
*/
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "d.dept_id"),
|
||||
@DataColumn(key = "userName", value = "u.user_id")
|
||||
})
|
||||
Page<SysUser> selectAllocatedList(@Param("page") Page<SysUser> page, @Param("user") SysUser user);
|
||||
|
||||
/**
|
||||
@ -38,6 +52,10 @@ public interface SysUserMapper extends BaseMapperPlus<SysUser> {
|
||||
* @param user 用户信息
|
||||
* @return 用户信息集合信息
|
||||
*/
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "d.dept_id"),
|
||||
@DataColumn(key = "userName", value = "u.user_id")
|
||||
})
|
||||
Page<SysUser> selectUnallocatedList(@Param("page") Page<SysUser> page, @Param("user") SysUser user);
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,24 @@
|
||||
package com.ruoyi.system.service;
|
||||
|
||||
/**
|
||||
* 通用 数据权限 服务
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
public interface SysDataScopeService {
|
||||
|
||||
/**
|
||||
* 获取角色自定义权限
|
||||
* @param roleId 角色id
|
||||
* @return 部门id组
|
||||
*/
|
||||
String getRoleCustom(Long roleId);
|
||||
|
||||
/**
|
||||
* 获取部门及以下权限
|
||||
* @param deptId 部门id
|
||||
* @return 部门id组
|
||||
*/
|
||||
String getDeptAndChild(Long deptId);
|
||||
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package com.ruoyi.system.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.ruoyi.common.core.domain.entity.SysDept;
|
||||
import com.ruoyi.system.domain.SysRoleDept;
|
||||
import com.ruoyi.system.mapper.SysDeptMapper;
|
||||
import com.ruoyi.system.mapper.SysRoleDeptMapper;
|
||||
import com.ruoyi.system.service.SysDataScopeService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service("sdss")
|
||||
public class SysDataScopeServiceImpl implements SysDataScopeService {
|
||||
|
||||
@Autowired
|
||||
private SysRoleDeptMapper roleDeptMapper;
|
||||
@Autowired
|
||||
private SysDeptMapper deptMapper;
|
||||
|
||||
@Override
|
||||
public String getRoleCustom(Long roleId) {
|
||||
List<SysRoleDept> list = roleDeptMapper.selectList(
|
||||
new LambdaQueryWrapper<SysRoleDept>()
|
||||
.select(SysRoleDept::getDeptId)
|
||||
.eq(SysRoleDept::getRoleId, roleId));
|
||||
if (CollUtil.isNotEmpty(list)) {
|
||||
return list.stream().map(rd -> Convert.toStr(rd.getDeptId())).collect(Collectors.joining(","));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDeptAndChild(Long deptId) {
|
||||
List<SysDept> list = deptMapper.selectList(new LambdaQueryWrapper<SysDept>()
|
||||
.select(SysDept::getDeptId)
|
||||
.eq(SysDept::getDeptId, deptId)
|
||||
.or()
|
||||
.apply("find_in_set({0},ancestors)", deptId));
|
||||
if (CollUtil.isNotEmpty(list)) {
|
||||
return list.stream().map(d -> Convert.toStr(d.getDeptId())).collect(Collectors.joining(","));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -5,7 +5,6 @@ import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.ruoyi.common.annotation.DataScope;
|
||||
import com.ruoyi.common.constant.UserConstants;
|
||||
import com.ruoyi.common.core.domain.entity.SysDept;
|
||||
import com.ruoyi.common.core.domain.entity.SysRole;
|
||||
@ -47,8 +46,9 @@ public class SysDeptServiceImpl extends ServicePlusImpl<SysDeptMapper, SysDept,
|
||||
* @return 部门信息集合
|
||||
*/
|
||||
@Override
|
||||
@DataScope(deptAlias = "d")
|
||||
public List<SysDept> selectDeptList(SysDept dept) {
|
||||
// return baseMapper.selectList();
|
||||
// return baseMapper.selectList(new LambdaQueryWrapper<>());
|
||||
return baseMapper.selectDeptList(dept);
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,6 @@ package com.ruoyi.system.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.common.annotation.DataScope;
|
||||
import com.ruoyi.common.constant.UserConstants;
|
||||
import com.ruoyi.common.core.domain.PageQuery;
|
||||
import com.ruoyi.common.core.domain.entity.SysRole;
|
||||
@ -46,7 +45,6 @@ public class SysRoleServiceImpl extends ServicePlusImpl<SysRoleMapper, SysRole,
|
||||
private SysRoleDeptMapper roleDeptMapper;
|
||||
|
||||
@Override
|
||||
@DataScope(deptAlias = "d")
|
||||
public TableDataInfo<SysRole> selectPageRoleList(SysRole role, PageQuery pageQuery) {
|
||||
Page<SysRole> page = baseMapper.selectPageRoleList(PageUtils.buildPage(pageQuery), role);
|
||||
return PageUtils.buildDataInfo(page);
|
||||
@ -59,7 +57,6 @@ public class SysRoleServiceImpl extends ServicePlusImpl<SysRoleMapper, SysRole,
|
||||
* @return 角色数据集合信息
|
||||
*/
|
||||
@Override
|
||||
@DataScope(deptAlias = "d")
|
||||
public List<SysRole> selectRoleList(SysRole role) {
|
||||
return baseMapper.selectRoleList(role);
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.common.annotation.DataScope;
|
||||
import com.ruoyi.common.constant.UserConstants;
|
||||
import com.ruoyi.common.core.domain.PageQuery;
|
||||
import com.ruoyi.common.core.domain.entity.SysRole;
|
||||
@ -54,7 +53,6 @@ public class SysUserServiceImpl extends ServicePlusImpl<SysUserMapper, SysUser,
|
||||
private SysUserPostMapper userPostMapper;
|
||||
|
||||
@Override
|
||||
@DataScope(deptAlias = "d", userAlias = "u", isUser = true)
|
||||
public TableDataInfo<SysUser> selectPageUserList(SysUser user, PageQuery pageQuery) {
|
||||
Page<SysUser> page = baseMapper.selectPageUserList(PageUtils.buildPage(pageQuery), user);
|
||||
return PageUtils.buildDataInfo(page);
|
||||
@ -67,7 +65,6 @@ public class SysUserServiceImpl extends ServicePlusImpl<SysUserMapper, SysUser,
|
||||
* @return 用户信息集合信息
|
||||
*/
|
||||
@Override
|
||||
@DataScope(deptAlias = "d", userAlias = "u", isUser = true)
|
||||
public List<SysUser> selectUserList(SysUser user) {
|
||||
return baseMapper.selectUserList(user);
|
||||
}
|
||||
@ -79,7 +76,6 @@ public class SysUserServiceImpl extends ServicePlusImpl<SysUserMapper, SysUser,
|
||||
* @return 用户信息集合信息
|
||||
*/
|
||||
@Override
|
||||
@DataScope(deptAlias = "d", userAlias = "u", isUser = true)
|
||||
public TableDataInfo<SysUser> selectAllocatedList(SysUser user, PageQuery pageQuery) {
|
||||
Page<SysUser> page = baseMapper.selectAllocatedList(PageUtils.buildPage(pageQuery), user);
|
||||
return PageUtils.buildDataInfo(page);
|
||||
@ -92,7 +88,6 @@ public class SysUserServiceImpl extends ServicePlusImpl<SysUserMapper, SysUser,
|
||||
* @return 用户信息集合信息
|
||||
*/
|
||||
@Override
|
||||
@DataScope(deptAlias = "d", userAlias = "u", isUser = true)
|
||||
public TableDataInfo<SysUser> selectUnallocatedList(SysUser user, PageQuery pageQuery) {
|
||||
Page<SysUser> page = baseMapper.selectUnallocatedList(PageUtils.buildPage(pageQuery), user);
|
||||
return PageUtils.buildDataInfo(page);
|
||||
|
@ -42,10 +42,10 @@
|
||||
<if test="status != null and status != ''">
|
||||
AND status = #{status}
|
||||
</if>
|
||||
<!-- 数据范围过滤 -->
|
||||
<if test="params.dataScope != null and params.dataScope != ''">
|
||||
AND ( ${params.dataScope} )
|
||||
</if>
|
||||
<!-- <!– 数据范围过滤 –>-->
|
||||
<!-- <if test="params.dataScope != null and params.dataScope != ''">-->
|
||||
<!-- AND ( ${params.dataScope} )-->
|
||||
<!-- </if>-->
|
||||
order by d.parent_id, d.order_num
|
||||
</select>
|
||||
|
||||
|
@ -60,10 +60,10 @@
|
||||
<if test="role.params.endTime != null and role.params.endTime != ''"><!-- 结束时间检索 -->
|
||||
and date_format(r.create_time,'%y%m%d') <= date_format(#{role.params.endTime},'%y%m%d')
|
||||
</if>
|
||||
<!-- 数据范围过滤 -->
|
||||
<if test="role.params.dataScope != null and role.params.dataScope != ''">
|
||||
AND ( ${role.params.dataScope} )
|
||||
</if>
|
||||
<!-- <!– 数据范围过滤 –>-->
|
||||
<!-- <if test="role.params.dataScope != null and role.params.dataScope != ''">-->
|
||||
<!-- AND ( ${role.params.dataScope} )-->
|
||||
<!-- </if>-->
|
||||
order by r.role_sort
|
||||
</select>
|
||||
|
||||
@ -88,10 +88,10 @@
|
||||
<if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
|
||||
and date_format(r.create_time,'%y%m%d') <= date_format(#{params.endTime},'%y%m%d')
|
||||
</if>
|
||||
<!-- 数据范围过滤 -->
|
||||
<if test="params.dataScope != null and params.dataScope != ''">
|
||||
AND ( ${params.dataScope} )
|
||||
</if>
|
||||
<!-- <!– 数据范围过滤 –>-->
|
||||
<!-- <if test="params.dataScope != null and params.dataScope != ''">-->
|
||||
<!-- AND ( ${params.dataScope} )-->
|
||||
<!-- </if>-->
|
||||
order by r.role_sort
|
||||
</select>
|
||||
|
||||
|
@ -108,10 +108,10 @@
|
||||
AND (u.dept_id = #{user.deptId} OR u.dept_id IN ( SELECT t.dept_id FROM sys_dept t WHERE find_in_set(#{user.deptId},
|
||||
ancestors) ))
|
||||
</if>
|
||||
<!-- 数据范围过滤 -->
|
||||
<if test="user.params.dataScope != null and user.params.dataScope != ''">
|
||||
AND ( ${user.params.dataScope} )
|
||||
</if>
|
||||
<!-- <!– 数据范围过滤 –>-->
|
||||
<!-- <if test="user.params.dataScope != null and user.params.dataScope != ''">-->
|
||||
<!-- AND ( ${user.params.dataScope} )-->
|
||||
<!-- </if>-->
|
||||
</select>
|
||||
|
||||
<select id="selectUserList" parameterType="SysUser" resultMap="SysUserResult">
|
||||
@ -142,10 +142,10 @@
|
||||
AND (u.dept_id = #{deptId} OR u.dept_id IN ( SELECT t.dept_id FROM sys_dept t WHERE find_in_set(#{deptId},
|
||||
ancestors) ))
|
||||
</if>
|
||||
<!-- 数据范围过滤 -->
|
||||
<if test="params.dataScope != null and params.dataScope != ''">
|
||||
AND ( ${params.dataScope} )
|
||||
</if>
|
||||
<!-- <!– 数据范围过滤 –>-->
|
||||
<!-- <if test="params.dataScope != null and params.dataScope != ''">-->
|
||||
<!-- AND ( ${params.dataScope} )-->
|
||||
<!-- </if>-->
|
||||
</select>
|
||||
|
||||
<select id="selectAllocatedList" parameterType="SysUser" resultMap="SysUserResult">
|
||||
|
Loading…
x
Reference in New Issue
Block a user