Mybatis-plus通过添加拦截器实现简单数据权限
作者:野风r
系统需要根据用户所属的公司,来做一下数据权限控制,具体一点,就是通过表中的company_id进行权限控制,项目使用的是mybatis-plus,所以通过添加拦截器的方式,修改查询sql,实现数据权限,本文就通过代码给大家详细的讲解一下,需要的朋友可以参考下
1 配置文件中的配置
# 数据权限配置 data-permission: # 不再数据权限的表,目前主要是公司信息表,和一些关联表 not-control-tables: role_menu,user_company,user_role # 权限控制表,即基于哪个表的数据来做权限区分,目前是公司信息表 base-table: company_info # 特殊的uri,不进行数据权限控制 not-control-uri: /checkCompany-post
2 在权限处理时,将请求 uri 放入到内存中
/** * 自定义权限处理 */ @Component @Slf4j public class CustomAuthorizationManager implements AuthorizationManager<RequestAuthorizationContext> { @Override public AuthorizationDecision check( Supplier<Authentication> authentication, RequestAuthorizationContext requestAuthorizationContext ) { // …… HttpServletRequest request = requestAuthorizationContext.getRequest(); String method = request.getMethod(); String path = request.getRequestURI(); // 将当前的请求的信息,放入到user中,用户后面的数据权限 LoginUser loginUser = (LoginUser) authentication.get().getPrincipal(); loginUser.setUri(path + "-" + method.toLowerCase()); // …… } }
另外,用户在的登录系统之后,有一个选择公司的动作,这时将用户选择的公司信息放入缓存中:
// …… // 缓存用户选择的公司 RBucket<String> bucket = redissonClient.getBucket(OPERATION_COMPANY + loginUserId); bucket.set(companyId, Duration.ofHours(2)); // ……
3 拦截器中的配置
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.toolkit.PluginUtils; import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor; import lombok.Data; import lombok.extern.slf4j.Slf4j; import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.operators.conditional.AndExpression; import net.sf.jsqlparser.parser.CCJSqlParserUtil; 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; import org.redisson.api.RBucket; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Component; import java.sql.SQLException; import java.util.Arrays; import java.util.List; /** * 数据权限控制 */ @Data @Component @Slf4j public class DataPermissionInterceptor implements InnerInterceptor { @Autowired private RedissonClient redissonClient; @Value("${data-permission.not-control-tables}") public String notControlTables; @Value("${data-permission.base-table}") public String baseTable; @Value("${data-permission.not-control-uri}") public String notControlUri; @Override public boolean willDoQuery( Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql ) throws SQLException { return InnerInterceptor.super.willDoQuery(executor, ms, parameter, rowBounds, resultHandler, boundSql); } @Override public void beforeQuery( Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql ) throws SQLException { log.debug("数据权限处理……"); Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (ObjectUtil.isNull(authentication)) { log.debug("数据权限处理, 未登录!"); return; } Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); LoginUser loginUser = (LoginUser) principal; String username = loginUser.getUsername(); // 如果是系统管理员,不需做作权限处理 if (SYSTEM_ADMINISTRATOR_ACCOUNT.equals(username)) { log.debug("数据权限处理,当前为管理员,不需要处理数据权限。"); return; } String uri = loginUser.getUri(); log.debug("数据权限处理,当前uri为:{}", uri); if (notControlUri.contains(uri)) { log.debug("数据权限处理,当前uri,不需要处理数据权限。"); return; } String sql = boundSql.getSql(); Select select; try { select = (Select) CCJSqlParserUtil.parse(sql); } catch (JSQLParserException e) { throw new RuntimeException(e); } // 系统自动生成的sql,一般都是单表查询,所以这里暂时不考虑复杂的情况 PlainSelect plainSelect = (PlainSelect) select.getSelectBody(); net.sf.jsqlparser.schema.Table table = (net.sf.jsqlparser.schema.Table) plainSelect.getFromItem(); String tableName = table.getName(); // 排除一些不需要控制的表 List<String> notControlTablesList = Arrays.asList(notControlTables.split(",")); if (notControlTablesList.contains(tableName.toLowerCase())) { log.debug("数据权限处理,当前表不做权限控制,table is {}", tableName); return; } String userId = loginUser.getUser().getPkId(); RBucket<String> bucket = redissonClient.getBucket(OPERATION_COMPANY + userId); String companyId = bucket.get(); if (StrUtil.isBlank(companyId)) { throw new BaseException("公司id不存在!"); } // 处理SQL语句 // 基础表,根据主键进行控制 log.debug("数据权限处理,处理之前的sql为: {}", sql); Expression where = plainSelect.getWhere(); Expression envCondition; try { if (baseTable.equals(tableName.toLowerCase())) { envCondition = CCJSqlParserUtil.parseCondExpression("PK_ID = " + companyId); } else { envCondition = CCJSqlParserUtil.parseCondExpression("COMPANY_ID = " + companyId); } } catch (JSQLParserException e) { throw new RuntimeException(e); } if (where == null) { plainSelect.setWhere(envCondition); } else { AndExpression andExpression = new AndExpression(where, envCondition); plainSelect.setWhere(andExpression); } sql = plainSelect.toString(); log.debug("数据权限处理,处理之后的sql为: {}", sql); PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql); mpBs.sql(sql); } }
4 启用插件
@Configuration @MapperScan("xxx.xxx.xx.mapper") public class MybatisPlusConfig { @Autowired private DataPermissionInterceptor dataPermissionInterceptor; /** * 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除) */ @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(dataPermissionInterceptor); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }
到此这篇关于Mybatis-plus通过添加拦截器实现简单数据权限的文章就介绍到这了,更多相关Mybatis-plus实现简单数据权限内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!