返回顶部
首页 > 资讯 > 精选 >Mybatisplus数据权限DataPermissionInterceptor怎么实现
  • 568
分享到

Mybatisplus数据权限DataPermissionInterceptor怎么实现

2023-07-02 16:07:12 568人浏览 八月长安
摘要

这篇文章主要讲解了“mybatisplus数据权限DataPermissionInterceptor怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Mybatisplus数据权限Dat

这篇文章主要讲解了“mybatisplus数据权限DataPermissionInterceptor怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Mybatisplus数据权限DataPermissionInterceptor怎么实现”吧!

一、源码分析

  • 继承抽象类JsqlParserSupport并重写processSelect方法。jsqlParser是一个SQL语句解析器,它将SQL转换为Java类的可遍历层次结构。plus中也引入了JSqlParser包,processSelect可以对Select语句进行处理。

  • 实现InnerInterceptor接口并重写beforeQuery方法。InnerInterceptor是plus的插件接口,beforeQuery可以对查询语句执行前进行处理。

  • DataPermissionHandler作为数据权限处理器,是一个接口,提供getSqlSegment方法添加数据权限 SQL 片段。

  • 由上可知,我们只需要实现DataPermissionHandler接口,并按照业务规则处理SQL,就可以实现数据权限的功能。

  • DataPermissionInterceptor为mybatis-plus 3.4.2版本以上才有的功能。

package com.baomidou.mybatisplus.extension.plugins.inner;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.handler.DataPermissionHandler;import lombok.*;import net.sf.jsqlparser.expression.Expression;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 org.apache.ibatis.executor.Executor;import org.apache.ibatis.mapping.BoundSql;import org.apache.ibatis.mapping.MappedStatement;import org.apache.ibatis.session.ResultHandler;import org.apache.ibatis.session.RowBounds;import java.sql.SQLException;import java.util.List;@Data@NoArgsConstructor@AllArgsConstructor@ToString(callSuper = true)@EqualsAndHashCode(callSuper = true)@SuppressWarnings({"rawtypes"})public class DataPermissionInterceptor extends JsqlParserSupport implements InnerInterceptor {    private DataPermissionHandler 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(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));        }    }        protected void setWhere(PlainSelect plainSelect, String whereSegment) {        Expression sqlSegment = dataPermissionHandler.getSqlSegment(plainSelect.getWhere(), whereSegment);        if (null != sqlSegment) {            plainSelect.setWhere(sqlSegment);        }    }}

二、使用案例

mybatis-plus在gitee的仓库中,有人询问了如何使用DataPermissionInterceptor,下面有人给出了例子,一共分为两步,一是实现dataPermissionHandler接口,二是将实现添加到mybstis-plus的处理器中。他的例子中是根据不同权限类型拼接sql。

通用的方案是在所有的表中增加权限相关的字段,如部门、门店、租户等。实现dataPermissionHandler接口时较方便,可直接添加这几个字段的条件,无需查询数据库

public class DataPermissionHandlerImpl implements DataPermissionHandler {    @Override    public Expression getSqlSegment(Expression where, String mappedStatementId) {        try {            Class<?> clazz = Class.forName(mappedStatementId.substring(0, mappedStatementId.lastIndexOf(".")));            String methodName = mappedStatementId.substring(mappedStatementId.lastIndexOf(".") + 1);            Method[] methods = clazz.getDeclaredMethods();            for (Method method : methods) {                DataPermission annotation = method.getAnnotation(DataPermission.class);                if (ObjectUtils.isNotEmpty(annotation) && (method.getName().equals(methodName) || (method.getName() + "_COUNT").equals(methodName))) {                    // 获取当前的用户                    LoginUser loginUser = springUtils.getBean(TokenService.class).getLoginUser(ServletUtils.getRequest());                    if (ObjectUtils.isNotEmpty(loginUser) && ObjectUtils.isNotEmpty(loginUser.getUser()) && !loginUser.getUser().isAdmin()) {                        return dataScopeFilter(loginUser.getUser(), annotation.value(), where);                    }                }            }        } catch (ClassNotFoundException e) {            e.printStackTrace();        }        return where;    }        public static Expression dataScopeFilter(SysUser user, String tableAlias, Expression where) {        Expression expression = null;        for (SysRole role : user.getRoles()) {            String dataScope = role.getDataScope();            if (DataScopeAspect.DATA_SCOPE_ALL.equals(dataScope)) {                return where;            }            if (DataScopeAspect.DATA_SCOPE_CUSTOM.equals(dataScope)) {                InExpression inExpression = new InExpression();                inExpression.setLeftExpression(buildColumn(tableAlias, "dept_id"));                SubSelect subSelect = new SubSelect();                PlainSelect select = new PlainSelect();                select.setSelectItems(Collections.singletonList(new SelectExpressionItem(new Column("dept_id"))));                select.setFromItem(new Table("sys_role_dept"));                EqualsTo equalsTo = new EqualsTo();                equalsTo.setLeftExpression(new Column("role_id"));                equalsTo.setRightExpression(new LongValue(role.getRoleId()));                select.setWhere(equalsTo);                subSelect.setSelectBody(select);                inExpression.setRightExpression(subSelect);                expression = ObjectUtils.isNotEmpty(expression) ? new OrExpression(expression, inExpression) : inExpression;            }            if (DataScopeAspect.DATA_SCOPE_DEPT.equals(dataScope)) {                EqualsTo equalsTo = new EqualsTo();                equalsTo.setLeftExpression(buildColumn(tableAlias, "dept_id"));                equalsTo.setRightExpression(new LongValue(user.getDeptId()));                expression = ObjectUtils.isNotEmpty(expression) ? new OrExpression(expression, equalsTo) : equalsTo;            }            if (DataScopeAspect.DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope)) {                InExpression inExpression = new InExpression();                inExpression.setLeftExpression(buildColumn(tableAlias, "dept_id"));                SubSelect subSelect = new SubSelect();                PlainSelect select = new PlainSelect();                select.setSelectItems(Collections.singletonList(new SelectExpressionItem(new Column("dept_id"))));                select.setFromItem(new Table("sys_dept"));                EqualsTo equalsTo = new EqualsTo();                equalsTo.setLeftExpression(new Column("dept_id"));                equalsTo.setRightExpression(new LongValue(user.getDeptId()));                Function function = new Function();                function.setName("find_in_set");                function.setParameters(new ExpressionList(new LongValue(user.getDeptId()) , new Column("ancestors")));                select.setWhere(new OrExpression(equalsTo, function));                subSelect.setSelectBody(select);                inExpression.setRightExpression(subSelect);                expression = ObjectUtils.isNotEmpty(expression) ? new OrExpression(expression, inExpression) : inExpression;            }            if (DataScopeAspect.DATA_SCOPE_SELF.equals(dataScope)) {                EqualsTo equalsTo = new EqualsTo();                equalsTo.setLeftExpression(buildColumn(tableAlias, "create_by"));                equalsTo.setRightExpression(new StringValue(user.getUserName()));                expression = ObjectUtils.isNotEmpty(expression) ? new OrExpression(expression, equalsTo) : equalsTo;            }        }        return ObjectUtils.isNotEmpty(where) ? new AndExpression(where, new Parenthesis(expression)) : expression;    }        public static Column buildColumn(String tableAlias, String columnName) {        if (StringUtils.isNotEmpty(tableAlias)) {            columnName = tableAlias + "." + columnName;        }        return new Column(columnName);    }}
// 自定义数据权限interceptor.addInnerInterceptor(new DataPermissionInterceptor(new DataPermissionHandlerImpl()));

尝试验证

DataPermissionHandler 接口

Mybatisplus数据权限DataPermissionInterceptor怎么实现

可以看到DataPermissionHandler 接口使用中,传递来的参数是什么。

参数含义
where为当前sql已有的where条件
mappedStatementId为mapper中定义的方法的路径

@InterceptorIgnore注解

拦截忽略注解 @InterceptorIgnore

属性名类型默认值描述
tenantLineString“”行级租户
dynamicTableNameString“”动态表名
blockAttackString“”攻击 SQL 阻断解析器,防止全表更新与删除
illegalSqlString“”垃圾SQL拦截

实践应用

在维修小程序中,我使用了此方案。如下是我的代码:

@Componentpublic class MyDataPermissionHandler implements DataPermissionHandler {    @Autowired    @Lazy    private UserRepository userRepository;    @Override    public Expression getSqlSegment(Expression where, String mappedStatementId) {        try {            Class<?> clazz = Class.forName(mappedStatementId.substring(0, mappedStatementId.lastIndexOf(".")));            String methodName = mappedStatementId.substring(mappedStatementId.lastIndexOf(".") + 1);            Method[] methods = clazz.getDeclaredMethods();            for (Method method : methods) {                if (!methodName.equals(method.getName())) {                    continue;                }                // 获取自定义注解,无此注解则不控制数据权限                CustomDataPermission annotation = method.getAnnotation(CustomDataPermission.class);                if (annotation == null) {                    continue;                }                // 自定义的用户上下文,获取到用户的id                ContextUserDetails contextUserDetails = UserDetailsContextHolder.getContextUserDetails();                String userId = contextUserDetails.getId();                User user = userRepository.selectUserById(userId);                // 如果是特权用户,不控制数据权限                if (Constants.ADMIN_RULE == user.getAdminuser()) {                    return where;                }                // 员工用户                if (UserTypeEnum.USER_TYPE_EMPLOYEE.getCode().equals(user.getUsertype())) {                // 员工用户的权限字段                    String field = annotation.field().getValue();                    // 单据类型                    String billType = annotation.billType().getFuncno();                    // 操作类型                    OperationTypeEnum operationType = annotation.operation();                    // 权限字段为空则为不控制数据权限                    if (StringUtils.isNotEmpty(field)) {                        List<DataPermission> dataPermissions = userRepository.selectUserFuncnoDataPermission(userId, billType);                        if (dataPermissions.size() == 0) {                            // 没数据权限,但有功能权限则取所有数据                            return where;                        }                        // 构建in表达式                        InExpression inExpression = new InExpression();                        inExpression.setLeftExpression(new Column(field));                        List<Expression> conditions = null;                        switch(operationType) {                            case SELECT:                                conditions = dataPermissions.stream().map(res -> new StringValue(res.getStkid())).collect(Collectors.toList());                                break;                            case INSERT:                                conditions = dataPermissions.stream().filter(DataPermission::isAddright).map(res -> new StringValue(res.getStkid())).collect(Collectors.toList());                                break;                            case UPDATE:                                conditions = dataPermissions.stream().filter(DataPermission::isModright).map(res -> new StringValue(res.getStkid())).collect(Collectors.toList());                                break;                            case APPROVE:                                conditions = dataPermissions.stream().filter(DataPermission::isCheckright).map(res -> new StringValue(res.getStkid())).collect(Collectors.toList());                                break;                            default:                                break;                        }                        if (conditions == null) {                            return where;                        }                        conditions.add(new StringValue(Constants.ALL_STORE));                        ItemsList itemsList = new ExpressionList(conditions);                        inExpression.setRightItemsList(itemsList);                        if (where == null) {                            return inExpression;                        }                        return new AndExpression(where, inExpression);                    } else {                        return where;                    }                } else {                // 供应商用户的权限字段                    String field = annotation.vendorfield().getValue();                    if (StringUtils.isNotEmpty(field)) {                    // 供应商如果控制权限,则只能看到自己的单据。直接使用EqualsTo                         EqualsTo equalsTo = new EqualsTo();                        equalsTo.setLeftExpression(new Column(field));                        equalsTo.setRightExpression(new StringValue(userId));                        if (where == null) {                            return equalsTo;                        }                        // 创建 AND 表达式 拼接Where 和 = 表达式                        return new AndExpression(where, equalsTo);                    } else {                        return where;                    }                }            }        } catch (ClassNotFoundException e) {            e.printStackTrace();        }        return where;    }}
@Configurationpublic class MybatisConfig {    @Autowired    private MyDataPermissionHandler myDataPermissionHandler;    @Bean    public MybatisPlusInterceptor mybatisPlusInterceptor() {        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();        // 添加数据权限插件        DataPermissionInterceptor dataPermissionInterceptor = new DataPermissionInterceptor();        // 添加自定义的数据权限处理器        dataPermissionInterceptor.setDataPermissionHandler(myDataPermissionHandler);        interceptor.addInnerInterceptor(dataPermissionInterceptor);        // 分页插件        //interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.SQL_SERVER));        return interceptor;    }}

因为维修小程序相当于一个外挂程序,他的权限控制延用了七八年前程序的方案,设计的较为复杂,也有现成获取数据的存储过程供我们使用,此处做了一些特殊处理。增加了自定义注解、dataPermissionHandler接口实现类查询了数据库调用存储过程获取权限信息等。

自定义注解

@Target({ElementType.METHOD, ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)public @interface CustomDataPermission {    PermissionFieldEnum field();    PermissionFieldEnum vendorfield();    BillTypeEnum billType();    OperationTypeEnum operation();}

使用注解

@Mapperpublic interface ApplyHMapper extends BaseMapper<ApplyHPo> {        @CustomDataPermission(field = PermissionFieldEnum.FIELD_STKID,            vendorfield = PermissionFieldEnum.FIELD_EMPTY,            billType = BillTypeEnum.APPLY_BILL,            operation = OperationTypeEnum.SELECT)    Page<ApplyHPo> selectApplyHs(IPage<ApplyHPo> page, @Param(Constants.WRAPPER) QueryWrapper<ApplyHPo> queryWrapper);        Page<ApplyHPo> selectApplyHsForVendor(IPage<ApplyHPo> page, @Param("vendorid") String vendorid, @Param(Constants.WRAPPER) QueryWrapper<ApplyHPo> queryWrapper);        @CustomDataPermission(field = PermissionFieldEnum.FIELD_STKID,            vendorfield = PermissionFieldEnum.FIELD_EMPTY,            billType = BillTypeEnum.APPLY_BILL,            operation = OperationTypeEnum.SELECT)    ApplyHPo selectApplyH(@Param("billNo") String billNo);        @InterceptorIgnore    ApplyHPo selectApplyHNoPermission(@Param("billNo") String billNo);        void saveApplyH(ApplyHPo applyHPo);}

最终的效果

2022-04-24 09:14:52.878 DEBUG 29254 --- [NIO-8086-exec-2] c.y.w.i.p.m.ApplyHMapper.selectApplyHs   : ==> select * from t_mt_apply_h WHERE stkid IN ('0025', 'all')

感谢各位的阅读,以上就是“Mybatisplus数据权限DataPermissionInterceptor怎么实现”的内容了,经过本文的学习后,相信大家对Mybatisplus数据权限DataPermissionInterceptor怎么实现这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

--结束END--

本文标题: Mybatisplus数据权限DataPermissionInterceptor怎么实现

本文链接: https://lsjlt.com/news/343056.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Mybatisplus数据权限DataPermissionInterceptor怎么实现
    这篇文章主要讲解了“Mybatisplus数据权限DataPermissionInterceptor怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Mybatisplus数据权限Dat...
    99+
    2023-07-02
  • Mybatis-plus数据权限DataPermissionInterceptor实现
    目录前言一、源码分析二、使用案例尝试验证@InterceptorIgnore注解实践应用总结前言 数据权限因分页问题,不可能通过代码对数据进行过滤处理,只能在数据库语句进行处理,而如...
    99+
    2024-04-02
  • 怎么使用MyBatisPlus拦截器实现数据权限控制
    这篇文章主要介绍“怎么使用MyBatisPlus拦截器实现数据权限控制”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“怎么使用MyBatisPlus拦截器实现数据权限控制”文章能帮助大家解决问题。前言...
    99+
    2023-07-05
  • MySQL数据权限的实现详情
    目录数据权限模型实现效果数据模型数据权限表结构授权维度表具体授权维度表(产品线)组件路由表角色表角色组件绑定表角色组件授权规则表(核心)实现过程代码实现自定义数据权限注解定义数据权限处理切面数据权限工具类查询组件规则Co...
    99+
    2022-08-12
    MySQL数据权限实现 MySQL数据权限
  • 基于Mybatis-Plus实现数据权限
    概念 数据权限是指对系统用户进行数据资源可见性的控制。实现不同角色登录系统所展示的操作数据范围不一样,达到角色与角色、用户与用户之间数据的隔离。例如:管理员可以看到所有的菜单,而普通用户只能看到部分菜...
    99+
    2023-09-01
    java spring boot mybatis
  • 数据设计之权限的实现
    目录前言RBAC模型数据权限数据规则关联资源、用户继续优化小结前言 在项目实际开发中我们不光要控制一个用户能访问哪些资源,还需要控制用户只能访问资源中的某部分数据。 控制一个用户能访...
    99+
    2022-11-13
    数据设计权限实现 数据权限
  • MYSQL数据库管理中怎么实现权限管理
    本篇文章为大家展示了MYSQL数据库管理中怎么实现权限管理,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。 MYSQL权限简介关于mysql的权限简单的理解就是m...
    99+
    2024-04-02
  • vue路由权限和按钮权限怎么实现
    这篇“vue路由权限和按钮权限怎么实现”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“vue路由权限和按钮权限怎么实现”文章吧...
    99+
    2023-06-30
  • 怎么用Springboot+mybatis-plus+注解实现数据权限隔离
    今天小编给大家分享一下怎么用Springboot+mybatis-plus+注解实现数据权限隔离的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们...
    99+
    2023-06-08
  • mybatisplus @DS怎么实现动态切换数据源
    今天小编给大家分享一下mybatisplus @DS怎么实现动态切换数据源的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一...
    99+
    2023-07-02
  • postgresql数据库权限怎么设置
    在postgresql中,权限可以通过以下几种方式进行设置: 使用GRANT命令授予用户或角色特定的权限,比如SELECT...
    99+
    2024-04-08
    postgresql
  • Springboot+mybatis-plus+注解实现数据权限隔离
    目录1.创建注解 2. 具体实现 1.创建注解 当此注解打在类上,不需要传参,该类下所有查询接口开启数据隔离;打在方法上默认开启数据隔离,传参为false则该方法关闭验证 @...
    99+
    2024-04-02
  • SpringCloud 微服务数据权限控制的实现
    目录一、 整体架构二、 实现流程三、 实现步骤1. 注解实现2. 注解使用3. 实现AuthStoreSupplier4. 实现AuthQuerySupplier5. 开启数据权限四...
    99+
    2024-04-02
  • MyBatis Plus 拦截器实现数据权限控制
    一、介绍 上篇文章介绍的MyBatis Plus 插件实际上就是用拦截器实现的,MyBatis Plus拦截器对MyBatis的拦截器进行了包装处理,操作起来更加方便 二、自定义拦截器 2.1、InnerInterceptor MyBati...
    99+
    2023-08-20
    mybatis java mysql
  • SpringBoot怎么整合Springsecurity实现数据库登录及权限控制
    这篇文章主要为大家展示了“SpringBoot怎么整合Springsecurity实现数据库登录及权限控制”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“SpringBoot怎么整合Springs...
    99+
    2023-06-22
  • MySQL中怎么实现权限管理
    MySQL中怎么实现权限管理,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。1.用户权限简介当我们创建过数据库用户后,还不能执行任何操作,需...
    99+
    2024-04-02
  • mysql 中怎么实现权限控制
    本篇文章给大家分享的是有关mysql 中怎么实现权限控制,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。概述mysql权限控制在不同的上下文和不...
    99+
    2024-04-02
  • Shiro Realm权限认证怎么实现
    这篇文章主要讲解了“Shiro Realm权限认证怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Shiro Realm权限认证怎么实现”吧!shiro下载要学习 shiro,我们首先...
    99+
    2023-06-19
  • java怎么实现管理员权限
    在Java中,可以使用以下几种方式实现管理员权限:1. 使用if-else语句或switch语句判断管理员权限:```javaStr...
    99+
    2023-08-24
    java
  • 数据权限筛选(RLS)的两种实现介绍
      在应用程序中,尤其是在统计的时候, 需要使用数据权限来筛选数据行。 简单的说,张三看张三部门的数据, 李四看李四部门的数据;或者员工只能看自己的数据, 经理可以看部门的数据。这个在微软的文档中叫Row Level Security,字...
    99+
    2018-05-06
    数据权限筛选(RLS)的两种实现介绍
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作