当前位置:

首页 > 编程开发 > 怎么用Springboot+mybatis-plus+注解实现数据权限隔离

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

1.创建注解当此注解打在类上,不需要传参,该类下所有查询接口开启数据隔离;打在方法上默认开启数据隔离,传参为false则该方法关闭验证/***数据权限验证注解*@authorxiaohua*@date2021/6/23*/@Documented@Target({METHOD,ANNOTATION_TYPE,TYPE})@Retention(RUNTIME)public@interfaceDataPermission{/***是否要进行数据权限隔离*/booleanisPermi()defaulttrue;

本文目录

    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.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;
            }
        }
    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发
    相关文章 更多
    联想 Tab Plus Gen 2 平板海外开售:12.1 英寸屏幕、JBL 九单元扬声器
    联想 Tab Plus Gen 2 平板海外开售:12.1 英寸屏幕、JBL 九单元扬声器

    联想TabPlusGen2海外上市,12.1英寸2.5K120HzIPS屏,天玑7400芯片,后盖集成JBL九单元扬声器及杜比全景声,圆形支架可自立,内置10200mAh电池+45W快充,预装Android16,8+128GB约3367元。

    酷态科6月24日推出神秘新品,有望为“CP模块风扇Plus”底座
    酷态科6月24日推出神秘新品,有望为“CP模块风扇Plus”底座

    酷态科6月24日将推出CP模块风扇Plus磁吸底座,通过Power-Pin接口使风扇支持充放电。风扇搭载30000RPM无刷电机,风速11m/s,内置双5000mAh电池,续航37小时,支持33W快充。

    酷态科官宣 6 月 24 日推出神秘新品,有望为“CP 模块风扇 Plus”桌面底座
    酷态科官宣 6 月 24 日推出神秘新品,有望为“CP 模块风扇 Plus”桌面底座

    酷态科6月24日将推出神秘新品,有望为CP模块风扇Plus的桌面底座。该风扇采用30000RPM电机,风速达11m/s,内置两块5000mAh电池,续航37小时,支持充放电及主流快充协议。新品或使风扇兼具吹风与充电功能。

    首创“证据锚定”技术,百川智能发布 M3 Plus
    首创“证据锚定”技术,百川智能发布 M3 Plus

    百川智能发布医疗大模型Baichuan-M3Plus,事实性幻觉率降至2.6%,创下全球最低纪录。首创“证据锚定”技术,实现医学结论可验证、可追溯。多项国际评测中超越GPT-5.2等领先模型,API调用成本较前代下降70%,性能表现卓越,堪称行业里程碑。

    联想Tab Plus 2代发布:9扬声器+10200mAh大电池
    联想Tab Plus 2代发布:9扬声器+10200mAh大电池

    联想TabPlus2代在韩国发布,搭载联发科天玑7400芯片,12.1英寸120Hz600尼特屏幕,9个JBL扬声器支持杜比全景声和蓝牙音箱模式。内置10200mAh电池,预装安卓16,承诺升级至安卓18。配备联想AI实时转写、智能阅读和AI笔记等功能。

    戴尔推出2026款灵越Plus 16英寸笔记本,7004元起
    戴尔推出2026款灵越Plus 16英寸笔记本,7004元起

    全新戴尔2026款灵越Plus16英寸笔记本正式发布,其搭载酷睿Ultra5-225U处理器,性能强劲,起售价为7004元,可享受国家补贴后最低仅需5698元。机身重1.94千克,配备1920×1200分辨率60HzIPS屏幕,接口含雷电4、HDMI2.1和RJ45网口,且扩展性强,非常适合办公与学习。

    券后184.3元,酷态科CP模块风扇Plus曜石黑配色开售
    券后184.3元,酷态科CP模块风扇Plus曜石黑配色开售

    酷态科今天正式开售了CP模块风扇Plus的「曜石黑」版本,定价199元。电商平台上的券后价格大概在184.3元,有兴趣的可以留意一下。 这款新品最大的亮点就是模块化可扩展设计,内部搭载一颗30000 RPM的新一代高速三相无刷电机,技术原理和高速吹风机用的电机类似。实测风速最高能到11m/s,配合T

    券后 184.3 元,酷态科 CP 模块风扇 Plus 曜石黑配色开售
    券后 184.3 元,酷态科 CP 模块风扇 Plus 曜石黑配色开售

    酷态科CP模块风扇Plus曜石黑配色正式开售,到手价仅184.3元。搭载30000RPM高速三相无刷电机与涡流增压技术,最大风速可达11m/s。内置两块5000mAh电池,续航时间长达37小时,支持33W输出及多种快充协议,还可当作移动电源使用。

    中兴畅行70 Plus手机发售:展锐T9100 + 8G + 256G售2099元
    中兴畅行70 Plus手机发售:展锐T9100 + 8G + 256G售2099元

    中兴畅行70Plus已正式发售,定价为两千零九十九元,搭载了展锐T9100处理器、8GB运存与256GB存储。配备了6.75英寸120Hz高刷新率LCD打孔屏,内置了6050mAh大容量电池并支持45W快充,后置了一千三百万像素主摄,还提供了AI键、红外遥控及无网通信功能。

    如何使用SQLPlus进行数据库管理
    如何使用SQLPlus进行数据库管理

    SQLPlus 是 Oracle 数据库的一个命令行工具,用于执行 SQL 查询、PL/SQL 程序以及管理数据库。以下是一些基本的 SQLPlus 命令和用法,用于数据库管理:开启SQLPlus:打开命令行界面(在Windows系统上为CMD或PowerShell,在Unix/Linux系统上为T

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。