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; } }