MyBatis-Plus数据权限

1,403 阅读1分钟

注:仅使用于MyBatis-Plus 3.4.0+

直接上实现

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.inner.InnerInterceptor
import net.sf.jsqlparser.expression.Expression
import net.sf.jsqlparser.expression.HexValue
import net.sf.jsqlparser.expression.LongValue
import net.sf.jsqlparser.expression.StringValue
import net.sf.jsqlparser.expression.operators.conditional.AndExpression
import net.sf.jsqlparser.expression.operators.relational.EqualsTo
import net.sf.jsqlparser.expression.operators.relational.ExpressionList
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.FromItem
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

/**
 * Created by @author x on 2021/7/30
 */
class CustomizeDataPermissionHandler : JsqlParserSupport(), InnerInterceptor {

    override fun beforeQuery(executor: Executor?, ms: MappedStatement?, parameter: Any?, rowBounds: RowBounds?, resultHandler: ResultHandler<*>?, boundSql: BoundSql?) {
        if (!InterceptorIgnoreHelper.willIgnoreDataPermission(ms!!.id)) {
            val mpBs = PluginUtils.mpBoundSql(boundSql)
            mpBs.sql(parserSingle(mpBs.sql(), ms.id))
        }
    }

    override fun processSelect(select: Select, index: Int, sql: String?, obj: Any?) {
        val threadLocal = DataAuthThreadLocalUtil.current() ?: return
        val plainSelect = select.selectBody as PlainSelect
        if (!plainSelect.joins.isNullOrEmpty()) {
            plainSelect.joins.forEach {
                val onExpression = it.onExpression
                it.onExpression = buildExpression(onExpression, it.rightItem, threadLocal)
            }
        }
        var where = plainSelect.where
        if (where == null) {
            where = HexValue(" 1 = 1 ")
        }
        val formItem = plainSelect.fromItem as Table
        plainSelect.where = buildExpression(where, formItem, threadLocal)
    }

    private fun buildExpression(where: Expression, formItem: FromItem, listTable: MutableList<TableInfo>): Expression {
        val table = formItem as Table
        var expression = where
        listTable.forEach {
            if (it.tableName == table.name) {
                val columns = it.columnData
                if (!columns.isNullOrEmpty()) {
                    columns.forEach { (key, value) ->
                        if (value.size > 1) {
                            val itemsList = ExpressionList()
                            val inValues = mutableListOf<Expression>()
                            value.forEach { va ->
                                inValues.add(this.changeDataType(va))
                            }
                            itemsList.expressions = inValues
                            expression = AndExpression(expression, InExpression(Column(formItem, key), itemsList))
                        } else {
                            val equalsTo = EqualsTo()
                            equalsTo.leftExpression = Column(formItem, key)
                            equalsTo.rightExpression = this.changeDataType(value[0])
                            expression = AndExpression(expression, equalsTo)
                        }
                    }
                }
            }
        }
        return expression
    }

    private fun changeDataType(value: Any): Expression {
        return if (value is String) {
            StringValue(value)
        } else {
            LongValue(value.toString())
        }
    }
}

配置

/**
 * Created by @author x on 2021/7/30
 */
@Configuration
class MybatisPlusConfig {

    @Bean
    fun mybatisPlusInterceptor(): MybatisPlusInterceptor {
        val interceptor = MybatisPlusInterceptor()
        // 数据权限
        interceptor.addInnerInterceptor(CustomizeDataPermissionHandler())
        return interceptor
    }
}

TableInfo

/**
 * Created by @author x on 2021/7/30
 */
class TableInfo(var tableName: String?, var columnData: MutableMap<String, MutableList<Any>>?)

DataAuthThreadLocalUtil

/**
 * Created by @author x on 2021/7/30
 */
class DataAuthThreadLocalUtil {

    companion object {
        private val threadLocal = ThreadLocal<MutableList<TableInfo>>()

        fun current(): MutableList<TableInfo>? {
            return threadLocal.get()
        }

        fun setTableInfo(tableInfo: MutableList<TableInfo>) {
            threadLocal.set(tableInfo)
        }

        fun clear() {
            threadLocal.remove()
        }
    }
}