mybatis-plus实现自动拼接业务权限

配置文件里面加上自定义的拦截器

package com.xueyi.common.web.config;

import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.DataPermissionInterceptor;
import com.github.pagehelper.PageInterceptor;
import com.xueyi.common.datascope.interceptor.XueYiDataScopeHandler;
import com.xueyi.common.web.handler.TenantLineHandler;
import com.xueyi.common.web.handler.XueYiMetaObjectHandler;
import com.xueyi.common.web.injector.CustomizedSqlInjector;
import com.xueyi.common.web.interceptor.CustomerInnerInterceptor;
import com.xueyi.common.web.interceptor.TenantLineInnerInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * MP配置
 *
 * @author xueyi
 */
@Configuration
public class XueYiMyBatisPlusConfig {

    @Autowired
    private XueYiDataScopeHandler dataScopeAspect;

    @Autowired
    private TenantLineHandler tenantLineHandler;

    /**
     * PageHelper分页配置
     */
    @Bean
    public PageInterceptor pageInterceptor() {
        return new PageInterceptor();
    }

    /**
     * 方法注入
     */
    @Bean
    public CustomizedSqlInjector customizedSqlInjector() {
        return new CustomizedSqlInjector();
    }

    /**
     * 自动填充
     */
    @Bean
    public GlobalConfig globalConfig() {
        GlobalConfig globalConfig = new GlobalConfig();
        globalConfig.setMetaObjectHandler(new XueYiMetaObjectHandler());
        return globalConfig;
    }

    /**
     * 插件配置
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 数据权限插件
        interceptor.addInnerInterceptor(new DataPermissionInterceptor(dataScopeAspect));
        // 租户控制插件
        interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(tenantLineHandler));
        // 禁全表更删插件
        interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
//        //客户权限的拼接
        interceptor.addInnerInterceptor(new CustomerInnerInterceptor());
        return interceptor;
    }
}

自定义的拦截器

(这里做的功能就是发现是查询的情况,先看看表是否需要进行客户权限控制的,如果是的话,去线程里面去取授权的客户,如果没有的话就去查询,然后塞到线程变量里面去)

package com.xueyi.common.web.interceptor;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.plugins.inner.BaseMultiTableInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import com.xueyi.common.cache.utils.DictUtil;
import com.xueyi.common.core.context.SecurityContextHolder;
import com.xueyi.common.core.i18n.MessageUtils;
import com.xueyi.common.core.utils.core.ObjectUtil;
import com.xueyi.common.core.web.result.R;
import com.xueyi.common.security.utils.SecurityUtils;
import com.xueyi.system.api.dict.feign.RemoteDictService;
import com.xueyi.system.api.domain.dto.UserCustomerDto;
import com.xueyi.system.api.domain.query.UserCustomerQuery;
import com.xueyi.system.api.feign.RemoteSystemUserCustomerService;
import lombok.Value;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.relational.InExpression;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.select.WithItem;
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 org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 针对客户权限的拦截器
 *
 * @author chenwen
 */
@Component
public class CustomerInnerInterceptor extends BaseMultiTableInnerInterceptor implements InnerInterceptor {


    @Resource
    private RemoteSystemUserCustomerService remoteUserCustomerService;

    private static final String CUSTOMER_ID_COLUMN = "customer_id";

    //需要进行客户控制的表
    private static final List<String> TABLE_LIST = List.of(
            "tms_trans_order",
            "tms_trans_shipment",
            "bms_rece_contract"
    );

    /**
     * 查询的拦截器
     * @param executor      Executor(可能是代理对象)
     * @param ms            MappedStatement
     * @param parameter     parameter
     * @param rowBounds     rowBounds
     * @param resultHandler resultHandler
     * @param boundSql      boundSql
     * @throws SQLException
     */
    @Override
    public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
           //首先不是客户忽略的(没有显示设置 其实都是客户不忽略的)
           if (!SecurityContextHolder.getCustomerIgnore()){
            //获取查询前的sql语句,用JsqlParserSupport把sql语句解析成对应的语法树
            PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql);
            mpBs.sql(this.parserSingle(mpBs.sql(), (Object) null));
           }
    }


    /**
     * 如果解析到select语句
     * @param select
     * @param index
     * @param sql
     * @param obj
     */
    @Override
    protected void processSelect(Select select, int index, String sql, Object obj) {
       String whereSegment = (String) obj;
        this.processSelectBody(select.getSelectBody(), whereSegment);
        List<WithItem> withItemsList = select.getWithItemsList();
        if (!ObjectUtil.isEmpty(withItemsList)) {
            withItemsList.forEach((withItem) -> {
                this.processSelectBody(withItem, whereSegment);
            });
        }
    }


    /**
     * 只对查询进行控制
     * @param sh                 StatementHandler(可能是代理对象)
     * @param connection         Connection
     * @param transactionTimeout transactionTimeout
     */
    @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.INSERT || sct == SqlCommandType.UPDATE || sct == SqlCommandType.DELETE) {
            //增删改查暂不处理
            return;
        }
    }

    /**
     * 额外添加条件
     * @param table        表对象
     * @param where        当前where条件
     * @param whereSegment 所属Mapper对象全路径
     * @return
     */
    @Override
    public Expression buildTableExpression(Table table, Expression where, String whereSegment) {
        // 检查是否需要添加 customer_id 条件
        if (isTableNeedCustomerId(table)) {
            List<Long> ids= SecurityContextHolder.getCustomerIdList();
            //先去当前的localthread里面那里是否有值,如果为null代表是没查过
            if (ids==null){
                ids= selectCustomerIds();
            }
            //有客户的情况下才拼接(客户这边的逻辑是如果没有授权客户代表全部客户)
            if (ObjectUtil.isNotEmpty(ids)){
             InExpression customerIdCondition = new InExpression();
             customerIdCondition.setLeftExpression(getAliasColumn(table,CUSTOMER_ID_COLUMN));
             customerIdCondition.setRightExpression(getRightExpression(ids));
             return customerIdCondition;
            }

        }
        return null;
    }


     //判断表是否需要加上客户权限的
     private boolean isTableNeedCustomerId(Table table) {
        // 判断哪些表需要添加 customer_id 条件
        return TABLE_LIST.contains(table.getName());
    }


     /**
     处理条件后面拼接的值,customerid in (1,2)
     */
    protected Column getRightExpression(List<Long> list) {
      StringBuilder values = new StringBuilder();
      values.append("(");
        for (int i = 0; i < list.size(); i++) {
            Long item = list.get(i);
              values.append(item);
              if (i< list.size()-1){
                    values.append(",");
              }
        }
     values.append(")");
     return new Column(values.toString());
    }


//      /**
//     * 表别名设置
//     * org_id 或 tableAlias.org_id
//     * @param table 表对象
//     * @return 字段
//     */
    protected Column getAliasColumn(Table table, String columnName) {
        StringBuilder column = new StringBuilder();
        if (table.getAlias() != null) {
            column.append(table.getAlias().getName()).append(".").append(columnName);
        }else{
            column.append(table.getName()).append(".").append(columnName);
        }
        return new Column(column.toString());
    }

    private List<Long> selectCustomerIds(){
        SecurityContextHolder.getCustomerIdList();
        UserCustomerQuery userCustomerQuery= new UserCustomerQuery();
        userCustomerQuery.setUserId(SecurityUtils.getUserId());
        if (ObjectUtil.isNull(remoteUserCustomerService)){
            remoteUserCustomerService= SpringUtil.getBean(RemoteSystemUserCustomerService.class);
        }


        R<List<UserCustomerDto>> userCustomerDtoList= remoteUserCustomerService.listInner(userCustomerQuery);
        if (userCustomerDtoList.isFail()){
             logger.error(MessageUtils.message("getAuthCustomerError"));
            throw  new RuntimeException(MessageUtils.message("getAuthCustomerError"));
        }

        //如果内容为空就塞空长度的集合(不要塞null)
        if (ObjectUtil.isEmpty(userCustomerDtoList.getData())){
            SecurityContextHolder.setCustomerIdList(Collections.emptyList());
            return Collections.emptyList();
        }else{
             List<Long> customerIds= userCustomerDtoList.getData().stream().map(UserCustomerDto::getCustomerId).collect(Collectors.toList());
             SecurityContextHolder.setCustomerIdList(customerIds);
             return customerIds;
        }
}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值