您的位置:首页 > 游戏 > 游戏 > 室内设计知名网站_南充个人急售二手房_新闻软文推广案例_广州seo公司排名

室内设计知名网站_南充个人急售二手房_新闻软文推广案例_广州seo公司排名

2025/4/23 11:02:32 来源:https://blog.csdn.net/weixin_41919486/article/details/147306042  浏览:    关键词:室内设计知名网站_南充个人急售二手房_新闻软文推广案例_广州seo公司排名
室内设计知名网站_南充个人急售二手房_新闻软文推广案例_广州seo公司排名

mybatils拦截器实现数据权限控制

  • 1、介绍
  • 2、代码实现
    • 2.1、自定义拦截器抽象类
    • 2.2、自定义注解
    • 2.2、拦截器类实现
    • 2.4、注册拦截器
    • 2.5、Mapper代码编写
  • 3、注意

1、介绍

本文提供一种实现数据权限控制的思路,
比如,组织用户只能看到本组织的数据。
项目用户只能看到项目数据。
用的是mybatis拦截器实现。下面代码是封装好的,可直接拿来用。

2、代码实现

2.1、自定义拦截器抽象类

AbstractInterceptor.java

import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.plugin.Interceptor;
import java.io.Serializable;public abstract class AbstractInterceptor implements Interceptor, Serializable {private static final long serialVersionUID = 1L;protected MappedStatement copyFromMappedStatement(MappedStatement ms,SqlSource newSqlSource) {MappedStatement.Builder builder = new MappedStatement.Builder(ms.getConfiguration(),ms.getId(), newSqlSource, ms.getSqlCommandType());builder.resource(ms.getResource());builder.fetchSize(ms.getFetchSize());builder.statementType(ms.getStatementType());builder.keyGenerator(ms.getKeyGenerator());if (ms.getKeyProperties() != null && ms.getKeyProperties().length != 0) {StringBuffer keyProperties = new StringBuffer();for (String keyProperty : ms.getKeyProperties()) {keyProperties.append(keyProperty).append(",");}keyProperties.delete(keyProperties.length() - 1, keyProperties.length());builder.keyProperty(keyProperties.toString());}builder.timeout(ms.getTimeout());builder.parameterMap(ms.getParameterMap());builder.resultMaps(ms.getResultMaps());builder.resultSetType(ms.getResultSetType());builder.cache(ms.getCache());builder.flushCacheRequired(ms.isFlushCacheRequired());builder.useCache(ms.isUseCache());return builder.build();}public static class BoundSqlSqlSource implements SqlSource {BoundSql boundSql;public BoundSqlSqlSource(BoundSql boundSql) {this.boundSql = boundSql;}@Overridepublic BoundSql getBoundSql(Object parameterObject) {return boundSql;}}
}

2.2、自定义注解

DataFilter自定义注解实现

import java.lang.annotation.*;@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataFilter {/*** 业务表别名*/String tableAlias() default "";/*** 业务表组织ID*/String orgId() default "org_id";
}

2.2、拦截器类实现

DataScopeInterceptor.java

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.druid.DbType;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.statement.*;
import com.alibaba.druid.sql.parser.SQLParserUtils;
import com.alibaba.druid.sql.parser.SQLStatementParser;
import com.google.common.base.Strings;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;import java.lang.reflect.Method;/*** mybatis权限过滤拦截器* 拦截Executor.query()方法实现数据过滤.*/
@Intercepts({@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class,RowBounds.class, ResultHandler.class}),@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class,RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class})})
public class DataScopeInterceptor extends AbstractInterceptor {private static final long serialVersionUID = 2466462106327347435L;private static final String SEPARATION_MARK = ";";private static final int MAPPED_STATEMENT_INDEX = 0;private static final int PARAMETER_INDEX = 1;private String dbType;@Overridepublic Object intercept(Invocation invocation) throws Throwable {final Object[] queryArgs = invocation.getArgs();final MappedStatement mappedStatement = (MappedStatement) queryArgs[MAPPED_STATEMENT_INDEX];final Object parameter = queryArgs[PARAMETER_INDEX];BoundSql boundSql = mappedStatement.getBoundSql(parameter);//获取dataFilterDataFilter dataFilter = getDataFilter(mappedStatement);if (dataFilter != null) {//拿到要执行的sqlStringBuilder bufferSql = new StringBuilder(boundSql.getSql().trim());if (bufferSql.lastIndexOf(SEPARATION_MARK) == bufferSql.length() - 1) {bufferSql.deleteCharAt(bufferSql.length() - 1);}String originalSql = bufferSql.toString();String tableAlias = dataFilter.tableAlias();if (Strings.isNullOrEmpty(dataFilter.tableAlias())) {/*** 这一引入的是com.alibaba.druid.sql.parser包下的类,主要用于解析sql的表别名* 如果不用这种方式,自己能解析出来也行,建议使用本中方式*/SQLStatementParser parser = SQLParserUtils.createSQLStatementParser(originalSql, dbType);SQLStatement statement = parser.parseStatement();SQLSelectStatement selectStatement = (SQLSelectStatement) statement;SQLSelectQuery selectQuery = selectStatement.getSelect().getQuery();if (selectQuery instanceof SQLSelectQueryBlock) {SQLSelectQueryBlock query = selectStatement.getSelect().getQueryBlock();if (query.getFrom().getAlias() != null) {tableAlias = query.getFrom().getAlias();} else {tableAlias = findTableAlias(query.getFrom());}}}/*** 拼接需要链接的权限语句*/String sqlFilter = getSqlFilter(tableAlias, dataFilter.orgId());/*** 将权限语句加入sql*/if (!Strings.isNullOrEmpty(sqlFilter)) {String condition = sqlFilter;String newSql = SQLUtils.addCondition(originalSql, condition, DbType.mysql);MappedStatement newMs = copyFromNewSql(mappedStatement, boundSql, newSql);queryArgs[MAPPED_STATEMENT_INDEX] = newMs;}}return invocation.proceed();}/*** 根据新sql重新组装MappedStatement对象*/private MappedStatement copyFromNewSql(MappedStatement mappedStatement, BoundSql boundSql, String sql) {BoundSql newBoundSql = new BoundSql(mappedStatement.getConfiguration(), sql, boundSql.getParameterMappings(),boundSql.getParameterObject());for (ParameterMapping mapping : boundSql.getParameterMappings()) {String prop = mapping.getProperty();if (boundSql.hasAdditionalParameter(prop)) {newBoundSql.setAdditionalParameter(prop, boundSql.getAdditionalParameter(prop));}}return copyFromMappedStatement(mappedStatement, new BoundSqlSqlSource(newBoundSql));}/*** 拼接需要链接的sql条件*/private static String getSqlFilter(String tableAlias, String orgField) {//todo 这个地方,如果你需要根据用户ID或者项目id过滤数据,都是可以自定义加的,本文章只写的根据组织ID过滤。//组织ID,从上下文中获取,此处我们写死long orgId = 7L;if (!Strings.isNullOrEmpty(tableAlias)) {tableAlias += ".";}String str = "";str += " (";//用户角色,用户组 (组织)str += tableAlias + orgField + " IN ( " + orgId + ")";str += ")";return str;}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}private DataFilter getDataFilter(MappedStatement mappedStatement) throws ClassNotFoundException {//1.通过请求的mapper 获取dataFilter注解DataFilter dataFilter = getDataFilterByMapper(mappedStatement);if (ObjectUtil.isNotNull(dataFilter)) {return dataFilter;}return dataFilter;}private DataFilter getDataFilterByMapper(MappedStatement mappedStatement) throws ClassNotFoundException {String id = mappedStatement.getId();String className = id.substring(0, id.lastIndexOf("."));String methodName = id.substring(id.lastIndexOf(".") + 1);final Class cls = Class.forName(className);final Method[] method = cls.getMethods();DataFilter dataFilter = null;for (Method me : method) {if ((me.getName().equals(methodName) || methodName.equals("count"))&& me.isAnnotationPresent(DataFilter.class)) {dataFilter = me.getAnnotation(DataFilter.class);break;}}return dataFilter;}private String findTableAlias(SQLTableSource from) {if (from instanceof SQLExprTableSource) {SQLExprTableSource tableSource = (SQLExprTableSource) from;return Strings.isNullOrEmpty(tableSource.getAlias())? tableSource.getExpr().toString(): tableSource.getAlias();} else if (from instanceof SQLJoinTableSource) {return findTableAlias(((SQLJoinTableSource) from).getLeft());}return null;}
}

2.4、注册拦截器

MybatisPlusConfig.java

import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;@ConditionalOnBean({SqlSessionFactory.class})
@Configuration
public class MybatisPlusConfig {@ResourceSqlSessionFactory sqlSessionFactory;@PostConstructpublic void addInterceptors() {sqlSessionFactory.getConfiguration().addInterceptor(new DataScopeInterceptor());}
}

2.5、Mapper代码编写

这个我只贴截图,根据自己的业务写就行了。
在对应的mapper上加上@DataFilter注解,表示该查询方法走权限过滤。

实际执行sql:“WHERE AA.org_id IN (7)”就是通过拦截器拼接上去的。

SELECT AA.id, AA.uuid, AA.ip, AA.name, AA.cpu , AA.memory FROM res_vm_custom AA WHERE AA.org_id IN (7)

在这里插入图片描述

3、注意

上面是在我本地测试环境使用的,并没有加入

https://blog.csdn.net/bzqwell/article/details/139014107

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com