千家信息网

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

发表于:2025-02-22 作者:千家信息网编辑
千家信息网最后更新 2025年02月22日,今天小编给大家分享一下怎么用Springboot+mybatis-plus+注解实现数据权限隔离的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希
千家信息网最后更新 2025年02月22日怎么用Springboot+mybatis-plus+注解实现数据权限隔离

今天小编给大家分享一下怎么用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 classNames;    @Override    public Object intercept(Invocation invocation) throws Throwable {        try {            LoginInfo user = tokenService.getLoginInfo();            if (user == null){                return invocation.proceed();            }            List deptIds = (List) Convert.toList(user.getDataScope());            if (deptIds == null){                deptIds = new ArrayList<>();            }            //反射扫包会比较慢,这里做了个懒加载            if (classNames == null) {                synchronized (LazyInit.class){                    if (classNames == null){                        //扫描指定包路径下所有包含指定注解的类                        Set> 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 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.parseCond_Expression(condition);            if (expression == null) {                plainSelect.setWhere(envCondition);            } else {                AndExpression andExpression = new And_Expression(expression, envCondition);                plainSelect.setWhere(andExpression);            }            return plainSelect.toString();        } catch (JSQLParserException e) {            logger.error("解析原SQL并构建新SQL错误:" + e);            return sql;        }    }

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

数据 注解 方法 权限 隔离 语句 路径 知识 篇文章 验证 全名 内容 条件 查询 不同 原始 很大 大部分 对象 就是 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 小型服务器怎么进入节能模式 桌面共享软件开发公司哪家好 网络安全扫描拍立得相册 粉丝生活网络技术服务 nba数据库统计知乎 采用汽车车载网络技术可以 网络安全手抄报怎样制作 泸州网络安全宣传 网络安全教育团日活动背景 爱如生拇指数据库 维普数据库的结果输出方式 手游德国服务器 知乎计算机网络技术开始学什么 数据库七万多行怎么优化数据 C语言程序设计和数据库技术 计算机网络技术设备怎样连接 电脑登录手机版我的世界服务器 wifi连接服务器无法进入游戏 菏泽拓客软件开发公司 计算机网络技术工作周志 金铲铲之战服务器满了 这么近 自带数据库网站模板下载地址 龙城软件开发 苏州应用软件开发教程 平安科技 中国互联网 数据库约束大于怎么书写 网络安全审查实施日期 b2b2c购物商城软件开发 误删数据库在哪找到 腾讯云服务器怎么下载java
0