数据权限通用设计方案

问题引出

最近,许多学员反馈项目中需要处理数据权限,但是不知道怎么处理比较合适。这篇手记将针对这个问题,给出一种比较通用且容易扩展的数据权限设计方案。

现状

目前流行的权限框架已经有支持数据权限的了,但是需要配置在接口和方法上,扩展性不是很好,那么怎样做能让扩展性最大化呢?

很容易想到的就是:将数据权限的控制放到数据库里存储,在权限拦截时先判断接口是否有权访问,在接口有权访问后,接下来根据配置的条件判断是否有权使用指定的参数值。(做的更高级些,可以对返回的结果进行检查,包含了某个值的某个对象不允许访问的话,也当做无权访问处理,这篇手记里暂时不考虑这个情况)。具体怎么做呢?

数据库设计

先从数据库表设计说起,首先定义一个数据权限控制表结构:

 CREATE TABLE `sys_acl_data` (
        `id` int(11) NOT NULL,
        `acl_id` int(11) NOT NULL COMMENT '对应权限表主键',
        `status` tinyint(4) NOT NULL DEFAULT 1 COMMENT '状态,1:可用,0:不可用',
        `param` varchar(20) NOT NULL DEFAULT '' COMMENT '参数',
        `operation` int(11) NOT NULL DEFAULT 0 COMMENT '操作类型,0;等于,1:大于,2:小于,3:大于等于,4:小于等于,5:包含,6:介于之间,。。。',
        `value1` varchar(100) NOT NULL DEFAULT '0',
        `value2` varchar(100) NOT NULL DEFAULT '0',
        `next_param_op` int(11) NOT NULL DEFAULT 0 COMMENT '后续有参数时连接的关系,0:没有其他参数控制,1:与&&,2:或||',
        `seq` tinyint(4) NOT NULL DEFAULT '0' COMMENT '顺序',
        PRIMARY KEY (`id`),
        INDEX `idx_acl_id` USING BTREE (`acl_id`)
    ) ENGINE=`InnoDB` COMMENT '数据权限表';

具体介绍一下每个字段含义:

主键 id;

acl_id 映射权限点表主键,代表每行记录是针对哪个权限点的;

status 代表当前这条配置是否有效,方便临时激活与禁用;

param 代表需要校验的参数名,允许一个请求有多个参数参与数据校验;如果参数复杂,比如包含对象,定义的参数可能为a.b.c 这种多级的形式,建议不要太复杂

operation 代表数据拦截的规则,使用数字代表是等于、大于、小于、大于等于、小于等于、包含、介于之间等,可以根据自己需要增加或减少支持的拦截规则

value1 和 value2 用来和param、operation组成一个关系表达式,比如:1<=a<2

next_param_op 字段根据需要使用,如果一个权限点支持多条数据规则时,连接两个规则之间的操作,|| 还是 &&

seq 字段用于某个权限点包含多条数据权限规则时的顺序

假设有这么一条数据,那么他的含义是:id为1(acl_id)的权限点,配置了一条有效(status=1)的数据规则,规则是:传入参数id(param)的值要大于(operation)10(value1)

数据权限校验逻辑

有了表结构后,接下来就是增加接口能对数据进行更新和获取了,然后有个页面能对其进行展示和新增操作了,这里就不占更多篇幅了,重点说一下逻辑的处理。

[权限课程里原生实现一套权限管理部分已经对权限点做的基本管理和权限拦截就不在这里重复说了,具体看视频和代码就可以了,这里重点说一下如何在已有的权限上进行数据权限的扩展。首先给出url拦截核心代码和权限校验的核心代码(单独看这段代码不去看课程的细节应该也能看懂个大概):

 自定义filter拦截url判断权限核心代码:
   public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        String servletPath = request.getServletPath();
        Map requestMap = request.getParameterMap();

        if (exclusionUrlSet.contains(servletPath)) {
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }

        SysUser sysUser = RequestHolder.getCurrentUser();
        if (sysUser == null) {
            log.warn("someone visit {}, but no login, parameter:{}", servletPath, JsonMapper.obj2String(requestMap));
            noAuth(request, response);
            return;
        }
        SysCoreService sysCoreService = ApplicationContextHelper.popBean(SysCoreService.class);
        if (!sysCoreService.hasUrlAcl(servletPath)) {
            log.warn("{} visit {}, but no login, parameter:{}", JsonMapper.obj2String(sysUser), servletPath, JsonMapper.obj2String(requestMap));
            noAuth(request, response);
            return;
        }

        filterChain.doFilter(servletRequest, servletResponse);
        return;
    }

    实际判断一个url是否可访问的核心代码:
    public boolean hasUrlAcl(String url) {
        if (isSuperAdmin()) { // 超级管理员直接允许访问
            return true;
        }
        List<SysAcl> aclList = sysAclMapper.getByUrl(url); // 取出符合条件的权限点
        if (CollectionUtils.isEmpty(aclList)) {  
            return true;
        }

        List<SysAcl> userAclList = getCurrentUserAclListFromCache();
        Set<Integer> userAclIdSet = userAclList.stream().map(acl -> acl.getId()).collect(Collectors.toSet());

        boolean hasValidAcl = false;
        // 规则:只要有一个权限点有权限,那么我们就认为有访问权限
        for (SysAcl acl : aclList) {    // -----------------------------------------------------  ①
            // 判断一个用户是否具有某个权限点的访问权限
            if (acl == null || acl.getStatus() != 1) { // 权限点无效
                continue;
            }
            hasValidAcl = true;
            if (userAclIdSet.contains(acl.getId())) {
                return true;           // ------------------------------------------------------  ②
            }
        }
        if (!hasValidAcl) {
            return true;              // -------------------------------------------------------  ③
        }
        return false;
    }

从代码的 ① 处,可以拿到实际要判断的权限点。在判断某个指定的权限点已经有权限访问时,代码的 ②、③处,需要加入数据权限的校验。

既然要校验参数了,那么就需要把参数传入 hasUrlAcl 这个方法。doFilter方法里的 Map requestMap = request.getParameterMap(); 的requestMap就是url的参数列表,这种方式对于某些特殊的post提交不是完全适用,比如通过body里传递json格式的参数。实际项目中怎么把参数传递到方法里,可以根据项目接口的实际定义来处理。

当hasUrlAcl拿到参数且判断指定的权限点有权访问时,去sys_acl_data表根据acl_id查询出有效的规则列表,逐条判断,这里注意许多细节的处理。1、单条规则的解读,2、多条规则间的逻辑与和或,3、参数带层级时的解读(a.b.c这种),实际中可以根据项目中接口的定义规范来决定处理的复杂度。这个实现后,当url有权访问时,没有数据规则或者数据规则校验通过时,这个url才算真正的有权访问。

这时,肯定有人会问,我的接口是这样定义的/a/{id}.json 这种的该如何做数据权限拦截呢?其实这种方式的接口,课程里目前稍微调整一下也可以支持,调整如下:

 SysAclMapper.xml:
    <select id="getByUrl" parameterType="string" resultMap="BaseResultMap">
        SELECT <include refid="Base_Column_List" />
        FROM sys_acl
        WHERE url = #{url} <!-- url is not null and url != '' and  #{url} REGEXP url-->
     </select>

注释的内容是开启正则匹配的,就是通过正则去匹配url,这里使用 url is not null and url != ‘’ and #{url} REGEXP url 代替 url = #{url} ,然后在配置每个权限点时使用正则去配置每个权限点的url就可以了,比如刚才url配置权限校验时可以配置成/a/[5_|6_].json。当然这种方式对权限管理员的正则表达式有一定的要求。这时,在取符合条件的url时校验不过的权限点就取不出来了。取不出来不能直接就当做有处理,可以考虑遇到这种的再配置一个通配(/a/*.json)的权限,每次匹配到这种通配的url时必须保证匹配一个包含正则的校验才算有权限就可以了。这个的细节可以自己做一些不同的处理,这里只提供一个大概的思路。

结尾

关于数据权限就先说到这里,个人认为上面的方式在扩展性方面会相对好一些,实现起来难度也不是很大,如有问题欢迎指出。

其他权限手记

学习资料分享

当然,只给予计划不给予学习资料的行为无异于耍流氓,### 如果你对网络安全入门感兴趣,那么你点击这里👉CSDN大礼包:《黑客&网络安全入门&进阶学习资源包》免费分享

如果你对网络安全感兴趣,学习资源免费分享,保证100%免费!!!(嘿客入门教程)

👉网安(嘿客)全套学习视频👈

我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了。

img

👉网安(嘿客红蓝对抗)所有方向的学习路线****👈

对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。

img

学习资料工具包

压箱底的好资料,全面地介绍网络安全的基础理论,包括逆向、八层网络防御、汇编语言、白帽子web安全、密码学、网络安全协议等,将基础理论和主流工具的应用实践紧密结合,有利于读者理解各种主流工具背后的实现机制。

在这里插入图片描述

面试题资料

独家渠道收集京东、360、天融信等公司测试题!进大厂指日可待!
在这里插入图片描述

👉嘿客必备开发工具👈

工欲善其事必先利其器。学习客常用的开发软件都在这里了,给大家节省了很多时间。

这份完整版的网络安全(客)全套学习资料已经上传至CSDN官方,朋友们如果需要点击下方链接也可扫描下方微信二v码获取网络工程师全套资料【保证100%免费】

在这里插入图片描述

如果你对网络安全入门感兴趣,那么你点击这里👉CSDN大礼包:《黑客&网络安全入门&进阶学习资源包》免费分享

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 有很多优秀的通用后台管理模板可供选择,以下是一些比较流行的: 1. Ant Design Pro:基于 Ant Design 设计语言的企业级中后台前端/设计解决方案。 2. Element-UI:Element-UI 的后台管理系统解决方案。 3. Vue-Element-Admin:基于 vue 和 element-ui 的后台管理系统解决方案。 4. NG-Zorro:基于 Ant Design of Angular 设计体系的企业级中后台应用解决方案。 5. Bootstrap Admin:基于 Bootstrap 的后台管理系统解决方案。 这些模板都具有不同的特色和功能,您可以根据自己的需求选择适合自己的模板。 ### 回答2: 通用后台管理模板是一种针对各种类型网站后台管理功能的模板,通过提供一系列预设的样式和功能,使网站管理员能够快速搭建和管理网站后台。 通用后台管理模板一般具备以下功能: 1. 用户管理:可以管理网站的注册用户,包括添加、删除、修改用户信息等功能。 2. 权限管理:可以定义不同用户角色的权限,并给予不同角色对应的功能访问权限。 3. 数据管理:可以对网站的各项数据进行管理和操作,包括文章、评论、图片等。 4. 数据统计:提供网站的访问统计和数据分析,如用户数量、访问量等数据展示和分析。 5. 消息通知:可以实现对用户的消息通知功能,包括站内信、邮件提醒等。 6. 系统设置:提供对网站的基本设置功能,如网站名称、LOGO、主题风格等。 7. 插件扩展:支持对后台功能进行插件扩展,可以根据具体需求自定义添加功能。 通用后台管理模板的优点是提供了一种快速、便捷的方式来搭建和管理网站后台,管理员无需从零开始开发,只需根据模板进行一些定制和配置,就能快速获得一个功能齐全的后台管理系统。同时,通用后台管理模板还具有较强的可扩展性和灵活性,可以根据实际需求进行功能的添加和修改,满足不同网站的特定需求。 总之,通用后台管理模板是一种方便、高效的网站后台管理解决方案,可以大大提升网站管理员的工作效率和用户管理能力。 ### 回答3: 通用后台管理模板是一种为企业或个人搭建和管理后台系统所设计的模板。它可以提供一个统一的界面和功能,方便用户进行业务管理和信息查询。该模板通常包含了常见的管理功能模块,如用户管理、权限管理、数据管理等,用户可以根据自己的需求进行定制和扩展。 通用后台管理模板具有以下特点: 1. 界面简洁美观:模板一般具有现代化的设计风格,界面简洁、美观,用户可以直观地进行操作。 2. 功能模块丰富:通用后台管理模板通常包含了常见的功能模块,如用户管理、权限管理、数据管理、日志管理等,用户可以根据实际需求选择使用。 3. 可定制和扩展:模板中的功能模块可以根据用户的需求进行定制和扩展,用户可以根据自己的业务逻辑添加或修改功能。 4. 响应式设计:模板通常采用响应式设计,可以适配不同尺寸的屏幕,如手机、平板电脑和电脑等,方便用户在不同设备上进行管理操作。 5. 易于使用和维护:通用后台管理模板一般具有良好的用户体验,简化了用户的学习成本,同时也方便系统的维护和更新。 总之,通用后台管理模板的出现极大地简化了企业和个人搭建后台系统的成本和工作量,同时也提高了管理效率和用户体验。它是一种快速搭建和管理后台系统的利器,对于很多企业和个人来说具有重要的价值和意义。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值