Mybatis-plus通过添加拦截器实现简单数据权限

 更新时间:2023年08月30日 09:20:25   作者:野风r  
系统需要根据用户所属的公司,来做一下数据权限控制,具体一点,就是通过表中的company_id进行权限控制,项目使用的是mybatis-plus,所以通过添加拦截器的方式,修改查询sql,实现数据权限,本文就通过代码给大家详细的讲解一下,需要的朋友可以参考下

1 配置文件中的配置

# 数据权限配置  
data-permission:  
  # 不再数据权限的表,目前主要是公司信息表,和一些关联表  
  not-control-tables: role_menu,user_company,user_role  
  # 权限控制表,即基于哪个表的数据来做权限区分,目前是公司信息表  
  base-table: company_info  
  # 特殊的uri,不进行数据权限控制  
  not-control-uri: /checkCompany-post

2 在权限处理时,将请求 uri 放入到内存中

/**  
 * 自定义权限处理  
 */  
@Component  
@Slf4j  
public class CustomAuthorizationManager implements AuthorizationManager<RequestAuthorizationContext> {  
    @Override  
    public AuthorizationDecision check(  
            Supplier<Authentication> authentication,  
            RequestAuthorizationContext requestAuthorizationContext  
    ) {  
	   // …… 
        HttpServletRequest request = requestAuthorizationContext.getRequest();  
        String method = request.getMethod();  
        String path = request.getRequestURI();  
        // 将当前的请求的信息,放入到user中,用户后面的数据权限  
        LoginUser loginUser = (LoginUser) authentication.get().getPrincipal();  
        loginUser.setUri(path + "-" + method.toLowerCase());  
	  // ……
    }
}

另外,用户在的登录系统之后,有一个选择公司的动作,这时将用户选择的公司信息放入缓存中:

// ……
// 缓存用户选择的公司  
RBucket<String> bucket = redissonClient.getBucket(OPERATION_COMPANY + loginUserId);  
bucket.set(companyId, Duration.ofHours(2));
// ……

3 拦截器中的配置

import cn.hutool.core.util.ObjectUtil;  
import cn.hutool.core.util.StrUtil;  
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;  
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;  
import lombok.Data;  
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 net.sf.jsqlparser.statement.select.PlainSelect;  
import net.sf.jsqlparser.statement.select.Select;  
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 org.redisson.api.RBucket;  
import org.redisson.api.RedissonClient;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.beans.factory.annotation.Value;  
import org.springframework.security.core.Authentication;  
import org.springframework.security.core.context.SecurityContextHolder;  
import org.springframework.stereotype.Component;  
import java.sql.SQLException;  
import java.util.Arrays;  
import java.util.List;  
/**  
 * 数据权限控制  
 */  
@Data  
@Component  
@Slf4j  
public class DataPermissionInterceptor implements InnerInterceptor {  
    @Autowired  
    private RedissonClient redissonClient;  
    @Value("${data-permission.not-control-tables}")  
    public String notControlTables;  
    @Value("${data-permission.base-table}")  
    public String baseTable;  
    @Value("${data-permission.not-control-uri}")  
    public String notControlUri;  
    @Override  
    public boolean willDoQuery(  
            Executor executor,  
            MappedStatement ms,  
            Object parameter,  
            RowBounds rowBounds,  
            ResultHandler resultHandler,  
            BoundSql boundSql  
    ) throws SQLException {  
        return InnerInterceptor.super.willDoQuery(executor, ms, parameter, rowBounds, resultHandler, boundSql);  
    }  
    @Override  
    public void beforeQuery(  
            Executor executor,  
            MappedStatement ms,  
            Object parameter,  
            RowBounds rowBounds,  
            ResultHandler resultHandler,  
            BoundSql boundSql  
    ) throws SQLException {  
        log.debug("数据权限处理……");  
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();  
        if (ObjectUtil.isNull(authentication)) {  
            log.debug("数据权限处理, 未登录!");  
            return;  
        }  
        Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();  
        LoginUser loginUser = (LoginUser) principal;  
        String username = loginUser.getUsername();  
        // 如果是系统管理员,不需做作权限处理  
        if (SYSTEM_ADMINISTRATOR_ACCOUNT.equals(username)) {  
            log.debug("数据权限处理,当前为管理员,不需要处理数据权限。");  
            return;  
        }  
        String uri = loginUser.getUri();  
        log.debug("数据权限处理,当前uri为:{}", uri);  
        if (notControlUri.contains(uri)) {  
            log.debug("数据权限处理,当前uri,不需要处理数据权限。");  
            return;  
        }  
        String sql = boundSql.getSql();  
        Select select;  
        try {  
            select = (Select) CCJSqlParserUtil.parse(sql);  
        } catch (JSQLParserException e) {  
            throw new RuntimeException(e);  
        }  
        // 系统自动生成的sql,一般都是单表查询,所以这里暂时不考虑复杂的情况  
        PlainSelect plainSelect = (PlainSelect) select.getSelectBody();  
        net.sf.jsqlparser.schema.Table table = (net.sf.jsqlparser.schema.Table) plainSelect.getFromItem();  
        String tableName = table.getName();  
        // 排除一些不需要控制的表  
        List<String> notControlTablesList = Arrays.asList(notControlTables.split(","));  
        if (notControlTablesList.contains(tableName.toLowerCase())) {  
            log.debug("数据权限处理,当前表不做权限控制,table is {}", tableName);  
            return;  
        }  
        String userId = loginUser.getUser().getPkId();  
        RBucket<String> bucket = redissonClient.getBucket(OPERATION_COMPANY + userId);  
        String companyId = bucket.get();  
        if (StrUtil.isBlank(companyId)) {  
            throw new BaseException("公司id不存在!");  
        }  
        // 处理SQL语句  
        // 基础表,根据主键进行控制  
        log.debug("数据权限处理,处理之前的sql为: {}", sql);  
        Expression where = plainSelect.getWhere();  
        Expression envCondition;  
        try {  
            if (baseTable.equals(tableName.toLowerCase())) {  
                envCondition = CCJSqlParserUtil.parseCondExpression("PK_ID = " + companyId);  
            } else {  
                envCondition = CCJSqlParserUtil.parseCondExpression("COMPANY_ID = " + companyId);  
            }  
        } catch (JSQLParserException e) {  
            throw new RuntimeException(e);  
        }  
        if (where == null) {  
            plainSelect.setWhere(envCondition);  
        } else {  
            AndExpression andExpression = new AndExpression(where, envCondition);  
            plainSelect.setWhere(andExpression);  
        }  
        sql = plainSelect.toString();  
        log.debug("数据权限处理,处理之后的sql为: {}", sql);  
        PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql);  
        mpBs.sql(sql);  
    }  
}

4 启用插件

  
@Configuration  
@MapperScan("xxx.xxx.xx.mapper")  
public class MybatisPlusConfig {  
    @Autowired  
    private DataPermissionInterceptor dataPermissionInterceptor;  
    /**  
     * 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)  
     */    @Bean  
    public MybatisPlusInterceptor mybatisPlusInterceptor() {  
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();  
        interceptor.addInnerInterceptor(dataPermissionInterceptor);  
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));  
        return interceptor;  
    }  
}

到此这篇关于Mybatis-plus通过添加拦截器实现简单数据权限的文章就介绍到这了,更多相关Mybatis-plus实现简单数据权限内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • JDBC编程的详细步骤

    JDBC编程的详细步骤

    这篇文章主要介绍了JDBC编程的详细步骤,文中有非常详细的代码示例,对正在学习JDBC编程的小伙伴们有很好的帮助,需要的朋友可以参考下
    2021-05-05
  • Spring Boot中使用jdbctemplate 操作MYSQL数据库实例

    Spring Boot中使用jdbctemplate 操作MYSQL数据库实例

    本篇文章主要介绍了Spring Boot中使用jdbctemplate 操作MYSQL数据库实例,具有一定的参考价值,有兴趣的可以了解一下。
    2017-04-04
  • 基于IDEA的Maven工程创建方式

    基于IDEA的Maven工程创建方式

    文章介绍了Maven工程的GAVP属性(GroupId、ArtifactId、Version、Packaging)及其格式规范,说明了Idea构建JavaSE/JavaEE工程的方法,并概述了Maven标准项目结构的作用与目录划分
    2025-07-07
  • Java异常分类以及几种处理机制分析讲解

    Java异常分类以及几种处理机制分析讲解

    在Java的广阔宇宙中,有一群特殊的“超级英雄”,它们在代码世界中穿梭,守护着程序的正常运行——它们就是“异常”,这些英雄们,各司其职,保护着程序免受错误的侵扰,今天,我们将深入这个神秘的世界,全面解析异常的分类,掌握异常的处理机制
    2024-07-07
  • idea中acitviti使用acitBPM插件出现乱码问题及解决方法

    idea中acitviti使用acitBPM插件出现乱码问题及解决方法

    这篇文章主要介绍了idea中acitviti使用acitBPM插件出现乱码问题及解决方法,通过将File Encodings内容设置为UTF-8,本文通过图文展示,需要的朋友可以参考下
    2021-06-06
  • 深入理解Thread.sleep(0)的作用

    深入理解Thread.sleep(0)的作用

    本文主要介绍了深入理解Thread.sleep(0)的作用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-09-09
  • java之生产故障定位Arthas问题

    java之生产故障定位Arthas问题

    这篇文章主要介绍了java之生产故障定位Arthas问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-06-06
  • Mybatis核心配置文件、默认类型别名、Mybatis获取参数值的两种方式(实例代码)

    Mybatis核心配置文件、默认类型别名、Mybatis获取参数值的两种方式(实例代码)

    这篇文章主要介绍了Mybatis核心配置文件、默认类型别名、Mybatis获取参数值的两种方式,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2024-03-03
  • Java Stream函数式编程管道流结果处理

    Java Stream函数式编程管道流结果处理

    这篇文章主要为大家介绍了Java Stream函数式编程管道流结果处理的示例过程解析需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2022-03-03
  • Spring Boot 中的默认异常处理机制解析(如 /error 接口)

    Spring Boot 中的默认异常处理机制解析(如 /error 接口)

    SpringBoot通过/error接口默认处理异常,使用BasicErrorController返回结构化JSON或HTML错误页面,支持自定义ErrorAttributes、ControllerAdvice及错误模板,配置项可调整错误路径和格式,本文给大家介绍Spring Boot 中的默认异常处理机制解析,感兴趣的朋友一起看看吧
    2025-07-07

最新评论