package cc.mrbird.febs.common.interceptor; 
 | 
  
 | 
import cc.mrbird.febs.common.annotation.DataPermission; 
 | 
import cc.mrbird.febs.common.utils.FebsUtil; 
 | 
import cc.mrbird.febs.system.entity.User; 
 | 
import com.baomidou.mybatisplus.core.toolkit.PluginUtils; 
 | 
import com.baomidou.mybatisplus.extension.handlers.AbstractSqlParserHandler; 
 | 
import lombok.extern.slf4j.Slf4j; 
 | 
import net.sf.jsqlparser.expression.operators.conditional.AndExpression; 
 | 
import net.sf.jsqlparser.parser.CCJSqlParserManager; 
 | 
import net.sf.jsqlparser.parser.CCJSqlParserUtil; 
 | 
import net.sf.jsqlparser.schema.Table; 
 | 
import net.sf.jsqlparser.statement.select.PlainSelect; 
 | 
import net.sf.jsqlparser.statement.select.Select; 
 | 
import org.apache.commons.lang3.StringUtils; 
 | 
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.plugin.*; 
 | 
import org.apache.ibatis.reflection.MetaObject; 
 | 
import org.apache.ibatis.reflection.SystemMetaObject; 
 | 
  
 | 
import java.io.StringReader; 
 | 
import java.sql.Connection; 
 | 
import java.util.Properties; 
 | 
  
 | 
/** 
 | 
 * @author MrBird 
 | 
 */ 
 | 
@Slf4j 
 | 
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})}) 
 | 
public class DataPermissionInterceptor extends AbstractSqlParserHandler implements Interceptor { 
 | 
  
 | 
    @Override 
 | 
    public Object intercept(Invocation invocation) throws Throwable { 
 | 
        StatementHandler statementHandler = PluginUtils.realTarget(invocation.getTarget()); 
 | 
        MetaObject metaObject = SystemMetaObject.forObject(statementHandler); 
 | 
        this.sqlParser(metaObject); 
 | 
        MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement"); 
 | 
  
 | 
        BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql"); 
 | 
        // 数据权限只针对查询语句 
 | 
        if (SqlCommandType.SELECT == mappedStatement.getSqlCommandType()) { 
 | 
            DataPermission dataPermission = getDataPermission(mappedStatement); 
 | 
            if (shouldFilter(mappedStatement, dataPermission)) { 
 | 
                String id = mappedStatement.getId(); 
 | 
                log.info("\n 数据权限过滤 Method -> {}", id); 
 | 
                String originSql = boundSql.getSql(); 
 | 
                String dataPermissionSql = dataPermissionSql(originSql, dataPermission); 
 | 
                metaObject.setValue("delegate.boundSql.sql", dataPermissionSql); 
 | 
                log.info("\n 原始SQL -> {} \n 数据权限过滤SQL -> {}", originSql, dataPermissionSql); 
 | 
            } 
 | 
        } 
 | 
        return invocation.proceed(); 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public Object plugin(Object target) { 
 | 
        if (target instanceof StatementHandler) { 
 | 
            return Plugin.wrap(target, this); 
 | 
        } 
 | 
        return target; 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public void setProperties(Properties properties) { 
 | 
    } 
 | 
  
 | 
    private String dataPermissionSql(String originSql, DataPermission dataPermission) { 
 | 
        try { 
 | 
            if (StringUtils.isBlank(dataPermission.field())) { 
 | 
                return originSql; 
 | 
            } 
 | 
            User currentUser = FebsUtil.getCurrentUser(); 
 | 
            if (currentUser == null) { 
 | 
                return originSql; 
 | 
            } 
 | 
            CCJSqlParserManager parserManager = new CCJSqlParserManager(); 
 | 
            Select select = (Select) parserManager.parse(new StringReader(originSql)); 
 | 
            PlainSelect plainSelect = (PlainSelect) select.getSelectBody(); 
 | 
            Table fromItem = (Table) plainSelect.getFromItem(); 
 | 
  
 | 
            String selectTableName = fromItem.getAlias() == null ? fromItem.getName() : fromItem.getAlias().getName(); 
 | 
            String dataPermissionSql = String.format("%s.%s in (%s)", selectTableName, dataPermission.field(), StringUtils.defaultIfBlank(currentUser.getDeptIds(), "'WITHOUT PERMISSIONS'")); 
 | 
  
 | 
            if (plainSelect.getWhere() == null) { 
 | 
                plainSelect.setWhere(CCJSqlParserUtil.parseCondExpression(dataPermissionSql)); 
 | 
            } else { 
 | 
                plainSelect.setWhere(new AndExpression(plainSelect.getWhere(), CCJSqlParserUtil.parseCondExpression(dataPermissionSql))); 
 | 
            } 
 | 
            return select.toString(); 
 | 
        } catch (Exception e) { 
 | 
            log.warn("get data permission sql fail: {}", e.getMessage()); 
 | 
            return originSql; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    private DataPermission getDataPermission(MappedStatement mappedStatement) { 
 | 
        String mappedStatementId = mappedStatement.getId(); 
 | 
        DataPermission dataPermission = null; 
 | 
        try { 
 | 
            String className = mappedStatementId.substring(0, mappedStatementId.lastIndexOf(".")); 
 | 
            final Class<?> clazz = Class.forName(className); 
 | 
            if (clazz.isAnnotationPresent(DataPermission.class)) { 
 | 
                dataPermission = clazz.getAnnotation(DataPermission.class); 
 | 
            } 
 | 
        } catch (Exception ignore) { 
 | 
        } 
 | 
        return dataPermission; 
 | 
    } 
 | 
  
 | 
    private Boolean shouldFilter(MappedStatement mappedStatement, DataPermission dataPermission) { 
 | 
        if (dataPermission != null) { 
 | 
            String methodName = StringUtils.substringAfterLast(mappedStatement.getId(), "."); 
 | 
            String methodPrefix = dataPermission.methodPrefix(); 
 | 
            if (StringUtils.isNotBlank(methodPrefix) && StringUtils.startsWith(methodName, methodPrefix)) { 
 | 
                return Boolean.TRUE; 
 | 
            } 
 | 
            String[] methods = dataPermission.methods(); 
 | 
            for (String method : methods) { 
 | 
                if (StringUtils.equals(method, methodName)) { 
 | 
                    return Boolean.TRUE; 
 | 
                } 
 | 
            } 
 | 
        } 
 | 
        return Boolean.FALSE; 
 | 
    } 
 | 
} 
 |