温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

怎么用Springboot+mybatis-plus+注解实现数据权限隔离

发布时间:2022-04-02 16:02:38 来源:亿速云 阅读:793 作者:iii 栏目:移动开发

今天小编给大家分享一下怎么用Springboot+mybatis-plus+注解实现数据权限隔离的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

1.创建注解

当此注解打在类上,不需要传参,该类下所有查询接口开启数据隔离;打在方法上默认开启数据隔离,传参为false则该方法关闭验证

/**  * 数据权限验证注解  * @author xiaohua  * @date 2021/6/23  */ @Documented @Target({METHOD, ANNOTATION_TYPE, TYPE}) @Retention(RUNTIME) public @interface DataPermission {     /**      * 是否要进行数据权限隔离      */     boolean isPermi() default true; }

2. 具体实现

@Component @Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})}) public class DataPermissionInterceptor implements Interceptor {     private static final Logger logger = LoggerFactory.getLogger(DataPermissionInterceptor.class);     @Autowired     private TokenService tokenService;     //扫描的包路径(根据自己的项目路径来),这里是取的配置里的包路径     @Value("${permission.package-path}")     private String packagePath;     private final static String DEPT_ID = "dept_id";     private final static String USER_ID = "create_user";     private static List<String> classNames;     @Override     public Object intercept(Invocation invocation) throws Throwable {         try {             LoginInfo user = tokenService.getLoginInfo();             if (user == null){                 return invocation.proceed();             }             List<Long> deptIds = (List<Long>) Convert.toList(user.getDataScope());             if (deptIds == null){                 deptIds = new ArrayList<>();             }             //反射扫包会比较慢,这里做了个懒加载             if (classNames == null) {                 synchronized (LazyInit.class){                     if (classNames == null){                         //扫描指定包路径下所有包含指定注解的类                         Set<Class<?>> classSet = ClassUtil.scanPackageByAnnotation(packagePath, DataPermission.class);                         if (classSet == null && classSet.size() == 0){                             classNames = new ArrayList<>();                         } else {                             //取得类全名                             classNames =  classSet.stream().map(Class::getName).collect(Collectors.toList());                         }                     }                 }             }             // 拿到mybatis的一些对象             StatementHandler statementHandler = PluginUtils.realTarget(invocation.getTarget());             MetaObject metaObject = SystemMetaObject.forObject(statementHandler);             MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");             // mappedStatement.getId()为执行的mapper方法的全路径名,newId为执行的mapper方法的类全名             String newId = mappedStatement.getId().substring(0, mappedStatement.getId().lastIndexOf("."));             // 如果不是指定的方法,直接结束拦截             if (!classNames.contains(newId)) {                 return invocation.proceed();             }             String newName = mappedStatement.getId().substring(mappedStatement.getId().lastIndexOf(".") + 1, mappedStatement.getId().length());             //是否开启数据权限             boolean isPermi = true;             Class<?> clazz = Class.forName(newId);             //遍历方法             for (Method method : clazz.getDeclaredMethods()) {                 //方法是否含有DataPermission注解,如果含有注解则将数据结果过滤                 if (method.isAnnotationPresent(DataPermission.class) && newName.equals(method.getName())) {                     DataPermission dataPermission =  method.getAnnotation(DataPermission.class);                     if (dataPermission != null) {                         //不验证                         if (!dataPermission.isPermi()) {                             isPermi = false;                         } else { //开启验证                             isPermi = true;                         }                     }                 }             }             if (isPermi){                 // 获取到原始sql语句                 String sql = statementHandler.getBoundSql().getSql();                 // 解析并返回新的SQL语句,只处理查询sql                 if (mappedStatement.getSqlCommandType().toString().equals("SELECT")) {     //                    String newSql = getNewSql(sql,deptIds,user.getUserId());                     sql = getSql(sql,deptIds,user.getUserId());                 }                 // 修改sql                 metaObject.setValue("delegate.boundSql.sql", sql);             }             return invocation.proceed();         } catch (Exception e){             logger.error("数据权限隔离异常:", e);             return invocation.proceed();         }     }               /**      * 解析SQL语句,并返回新的SQL语句      * 注意,该方法使用了JSqlParser来操作SQL,该依赖包Mybatis-plus已经集成了。如果要单独使用,请先自行导入依赖      *      * @param sql 原SQL      * @return 新SQL      */     private String getSql(String sql,List<Long> deptIds,Long userId) {         try {             String condition = "";             String permissionSql = "(";             if (deptIds.size() > 0){                 for (Long deptId : deptIds) {                     if ("(".equals(permissionSql)){                         permissionSql = permissionSql + deptId;                     } else {                         permissionSql = permissionSql + "," + deptId;                     }                 }                 permissionSql = permissionSql + ")";                 // 修改原语句                 condition = DEPT_ID +" in " + permissionSql;             } else {                 condition = USER_ID +" = " + userId;             }             if (StringUtils.isBlank(condition)){                 return sql;             }             Select select = (Select)CCJSqlParserUtil.parse(sql);             PlainSelect plainSelect = (PlainSelect)select.getSelectBody();             //取得原SQL的where条件             final Expression expression = plainSelect.getWhere();             //增加新的where条件             final Expression envCondition = CCJSqlParserUtil.parseCondExpression(condition);             if (expression == null) {                 plainSelect.setWhere(envCondition);             } else {                 AndExpression andExpression = new AndExpression(expression, envCondition);                 plainSelect.setWhere(andExpression);             }             return plainSelect.toString();         } catch (JSQLParserException e) {             logger.error("解析原SQL并构建新SQL错误:" + e);             return sql;         }     }

以上就是“怎么用Springboot+mybatis-plus+注解实现数据权限隔离”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注亿速云行业资讯频道。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI