精华内容
下载资源
问答
  • 在做导航菜单那块时,发现数据库里将权限表设计成一张了,此时再改数据库会牵一发而动全身,如果直接用递归的方式将权限封装成树,那么会将增删查之类的权限也变成导航菜单的一部分,也就是说查出来的“删除用户”、...

    遇到的情况是:在做导航菜单那块时,发现数据库里将权限表设计成一张了,此时再改数据库会牵一发而动全身,如果直接用递归的方式将权限封装成树,那么会将增删查之类的权限也变成导航菜单的一部分,也就是说查出来的“删除用户”、“添加角色”等权限也会出现在children里。

    解决方法:在递归时,将查出来的所有权限结果过滤,将增删改等子功能放在一个单独的list里(下文中的permitFunc中)。

    具体做法:

    1. 给数据库的权限表增加字段isMenu,用来区别是否是导航菜单(1表示是导航菜单,0表示不能出现在导航菜单的权限功能),还是增删改等功能,如下(请忽略父子关系的不合理):

     2. 写sql语句,一个是用来查询某用户的导航菜单(即isMenu是1),另一个是用来查该用户的其他权限(即isMenu是0),如下:

    3. 将用户的导航菜单全部查出来,并排序:

    目前的menuList如下:

    4. 按照前端所需的树结构存放,并将将查出来的所有权限结果过滤,将增删改等子功能放在一个单独的list(permitFunc)里:

    findTree里是这样的:

      /**
         * 将数据库中查询到的菜单list转为菜单树list
         *
         * @param allMenu
         * @return
         */
        private Map<String, Object> findTree(List<Permission> allMenu,String userName) {
            Map<String, Object> data = new HashMap<String, Object>();
            try {//查询所有菜单
                //根节点
                List<NavigatMenuVo> rootMenu = new ArrayList<NavigatMenuVo>();
                for (Permission nav : allMenu) {
                    NavigatMenuVo navigatMenuVo = new NavigatMenuVo();
                    Integer ss = nav.getPid();
                    if (nav.getPid() == 0) {//父节点是0的,为根节点。
                        navigatMenuVo.setChildren(nav.getChildren());
                        navigatMenuVo.setId(nav.getId());
                        navigatMenuVo.setLevel(nav.getLevel());
                        navigatMenuVo.setPermTag(nav.getPermTag());
                        navigatMenuVo.setTitle(nav.getPermName());
                        navigatMenuVo.setUrl(nav.getUrl());
                        rootMenu.add(navigatMenuVo);
                        break;
                    }
                }
                //为根菜单设置子菜单,getClild是递归调用的
                for (NavigatMenuVo navigatMenuVo2 : rootMenu) {
                    /* 获取根节点下的所有子节点 使用getChild方法*/
                    List<NavigatMenuVo> childList = getChild(navigatMenuVo2.getId(), allMenu,userName);
                    // 将查出来的所有权限结果过滤,将增删改等子功能放在一个单独的list里(permitFunc中)
                    List<NavigatMenuVo> permitFuncs = userMapper.findFuncPermissionByUsername(navigatMenuVo2.getId(),userName);
                    navigatMenuVo2.setPermitFunc(permitFuncs);
                    navigatMenuVo2.setChildren(childList);//给根节点设置子节点
                }
                /**
                 * 输出构建好的菜单数据。
                 *
                 */
                data.put("success", "true");
                data.put("list", rootMenu);
                return data;
            } catch (Exception e) {
                data.put("success", "false");
                data.put("list", new ArrayList());
                return data;
            }
        }
    
        private List<NavigatMenuVo> getChild(Integer id, List<Permission> allMenu,String userName) {
            //子菜单
            List<NavigatMenuVo> childList = new ArrayList<NavigatMenuVo>();
            List<NavigatMenuVo> permitList = new ArrayList<>();
            for (Permission nav : allMenu) {
                NavigatMenuVo navigatMenuVo = new NavigatMenuVo();
                // 遍历所有节点,将所有菜单的父id与传过来的根节点的id比较
                //相等说明:为该根节点的子节点。
                if (nav.getPid() == id) {
                    navigatMenuVo.setChildren(nav.getChildren());
                    navigatMenuVo.setId(nav.getId());
                    navigatMenuVo.setLevel(nav.getLevel());
                    navigatMenuVo.setPermTag(nav.getPermTag());
                    navigatMenuVo.setTitle(nav.getPermName());
                    navigatMenuVo.setUrl(nav.getUrl());
                    // 下面注释掉的这行其实等同于再下面的这行
                    // List<Permission> permitFuncs2 = allMenu.stream().filter(c->c.getIsMenu().equals(0) && c.getPid().equals(navigatMenuVo.getId())).collect(Collectors.toList());
                    // 将查出来的所有权限结果过滤,将增删改等子功能放在一个单独的list里(permitFunc中)
                    List<NavigatMenuVo> permitFuncs =  userMapper.findFuncPermissionByUsername(navigatMenuVo.getId(),userName);
                    navigatMenuVo.setPermitFunc(permitFuncs);
                    childList.add(navigatMenuVo);
                }
            }
    
            //递归
            for (NavigatMenuVo navigatMenuVo : childList) {
                navigatMenuVo.setChildren(getChild(navigatMenuVo.getId(), allMenu,userName));
            }
            //如果节点下没有子节点,返回一个空List(递归退出)
            if (childList.size() == 0) {
                return new ArrayList<NavigatMenuVo>();
            }
            return childList;
        }
    

    最后得到的结果如下:

    {
        "rtnCode": 200,
        "msg": "success",
        "data": [
            {           
                "id": 1,
                "title": "权限管理",
                "level": 0,
                "permitFunc": [
                    {     
                        "id": 19,
                        "title": "添加计划信息",
                        "level": 1,
                        "permitFunc": null,
                        "children": null
                    },
                    {   
                        "id": 20,
                        "title": "计划信息excel文件上传",
                        "level": 1,
                        "permitFunc": null,
                        "children": null
                    },
                    {
                        "id": 21,
                        "title": "根据token获取用户信息",
                        "level": 1,
                        "permitFunc": null,
                        "children": null
                    },
                    {
                        "id": 22,
                        "title": "根据token获取任务统计信息",
                        "level": 1,
                        "permitFunc": null,
                        "children": null
                    },
                    {
                        "id": 23,
                        "title": "添加日程日志",
                        "level": 1,
                        "permitFunc": null,
                        "children": null
                    },
                    {
                        "id": 24,
                        "title": "更新日程退出时间",
                        "level": 1,
                        "permitFunc": null,
                        "children": null
                    },
                    {
                        "id": 25,
                        "title": "查询日程日志",
                        "level": 1,
                        "permitFunc": null,
                        "children": null
                    }
                ],
                "children": [
                    {
                        "id": 2,
                        "title": "用户管理",
                        "level": 1,
                        "permitFunc": [
                            {
                                "id": 6,
                                "title": "添加用户",
                                "level": 2,
                                "permitFunc": null,
                                "children": null
                            },
                            {  
                                "id": 7,
                                "title": "修改用户",
                                "level": 2,
                                "permitFunc": null,
                                "children": null
                            },
                            {   
                                "id": 8,
                                "title": "删除用户",
                                "level": 2,
                                "permitFunc": null,
                                "children": null
                            }
                        ],
                        "children": []
                    },
                    {   
                        "id": 3,
                        "title": "角色管理",
                        "level": 1,
                        "permitFunc": [
                            {  
                                "id": 10,
                                "title": "添加角色",
                                "level": 2,
                                "permitFunc": null,
                                "children": null
                            },
                            {  
                                "id": 11,
                                "title": "修改角色",
                                "level": 2,
                                "permitFunc": null,
                                "children": null
                            },
                            {       
                                "id": 12,
                                "title": "删除角色",
                                "level": 2,
                                "permitFunc": null,
                                "children": null
                            }
                        ],
                        "children": []
                    },
                    {    
                        "id": 4,
                        "title": "菜单管理",
                        "level": 1,
                        "permitFunc": [
                            {     
                                "id": 14,
                                "title": "添加菜单",
                                "level": 2,
                                "permitFunc": null,
                                "children": null
                            },
                            {      
                                "id": 15,
                                "title": "修改菜单",
                                "level": 2,
                                "permitFunc": null,
                                "children": null
                            },
                            {      
                                "id": 16,
                                "title": "删除菜单",
                                "level": 2,
                                "permitFunc": null,
                                "children": null
                            }
                        ],
                        "children": []
                    }
                ]
            }
        ]
    }

    总结:其实这种解决方法还是很笨拙,可以进一步优化,比如用sql查询时就是直接封装好,再比如只用写一个sql,然后在利用

    stream().filter()过滤查询结果。不过总的来说,在设计数据库表的时候就应该考虑到这点,将权限表拆分成两张表,一张存放导航里要显示的权限,另一张来存放其他权限。编程之路很辛苦,还请各位多多指教!
    展开全文
  • 一般来说,权限有许多种,我们经常用到的一般有操作权限和数据权限两种。 所谓操作权限就是有或者没有做某种操作的权限,具体表现形式就是你看不到某个菜单或按钮,当然也有的是把菜单或按钮灰掉的形式。实际上它的...

    一般来说,权限有许多种,我们经常用到的一般有操作权限和数据权限两种。

    所谓操作权限就是有或者没有做某种操作的权限,具体表现形式就是你看不到某个菜单或按钮,当然也有的是把菜单或按钮灰掉的形式。实际上它的实现机制比表面上看到的要复杂得多,比如:我们从浏览器访问过一个地址之后,实际上这个URL就会在历史中存在,这时就会存在一种可能,有的人虽然没有权限,但是他知道怎么访问的URL,如果他再有一定的技术基础,那么通过猜测,有时候就可以得到真正的操作的URL,这个时候如果操作权限限制做得不到位,那么他就可能做他非授权的事项,所以操作权限一般都在显示界面做一次控制,过滤没有权限的操作菜单或按钮,另外在真正执行操作时,还要进行一次权限检查,确保控制非授权访问。

    所谓数据权限,就是有或者没有对某些数据的访问权限,具体表现形式就是当某用户有操作权限的时候,但不代表其对所有的数据都有查看或者管理权限。数据权限有两种表现形式:一种是行权限、另外一种是列权限。所谓行权限,就是限制用户对某些行的访问权限,比如:只能对本人、本部门、本组织的数据进行访问;也可以是根据数据的范围进行限制,比如:合同额大小来限制用户对数据的访问。所谓列权限,就是限制用户对某些列的访问权限,比如:某些内容的摘要可以被查阅,但是详细内容就只有VIP用户才能查看。通过数据权限,可以从物理层级限制用户对数据的行或列进行获取,这种方式比把所有数据拿到之后再根据用户权限来限制某些行或列有诸多好处:

     

    • 性能提升:获取的数据量较少,节省了网络流量和数据库IO,一定程度上可以提升性能
    • 翻页处理更为准确:如果通过后续逻辑去掉某些行,就会导致一页显示的记录条数不足,或者采用这条记录只显示部分内容,但是操作权限方面做限制的方式,这个时候就产生一个悖论,你不想让我操作,为什么让我看到?你让我看到为什么不让我操作?
    • 安全风险提升:理论上让攻击者看到的信息越多,被攻击的风险也越大。通过后续业务逻辑限制的方式通过攻击控制层或展现层的代码,理论上就可以获取到所有的数据。
    • 代码编写工作量增加:由于数据是正常全部返回的,只是通过后期的逻辑进行了控制,这个时候就需要开发人员增加相关的代码来进行判断和控制,这个时候会把高层级的限制逻辑暴露给底层业务开发人员,并由他们来编写代码进行限制。
    • 代码重构工作量增加:当权限限制逻辑或范围有变化的时候,程序员们就需要对这部分逻辑进行重构,稍不注意就会出现数据安全问题。

    操作权限相对来说比较简单,目前也有比较好的解决方案,因此今天的不讨论操作权限,今天重点来讨论数据权限的实现方案。

    需求整理

    一个好的数据权限方案要考虑哪些问题呢?我觉得要考虑以下方面:

     

    • 对程序员透明:整个方案对于程序员们来说,不论是前台还是后台的程序员们来说,越透明越好,他们最好不知道有这么回事情
    • 与不同的用户权限能较好集成:作为一个数据权限系统来说,肯定要和用户、角色、组织机构什么的数据打交道。如果这个方案只能和某一种用户权限系统集成,那么它充其量只能算是一个可用的解决方案,但是注定算不是上好的解决方案。
    • 性能损失最少:我们说,要增加新的功能或限制的过程中,肯定会对性能方面有一定影响的,怎么样能把性能损失降低,甚至能提升一定的性能是设计师们永恒的主题。
    • 对于分页能良好支持:上面有说到当采用了行权限时,有些行是不能显示给用户的,这个时候不能对分页有影响,比如本来是一页是10条的,现在忽然变成8条,甚至在极端情况下变成0条,这样的用户体验就非常差了。
    • 一次设定到处生效,哪怕是不同的ORMapping方案也都起作用:我们知道,现在采用唯一的一种ORMapping解决方案的场景已经越来越少了,不同的方案都有自己的优缺点,它可能只适应某种前置条件下的应用场景,实际应用的情况下根据场景不同使用不同的解决方案也是非常普遍的,这就要求解决方案有一定的普适定。
    • 跨数据库:一个项目,它的运行环境基本上是确定的。但是对于一个产品来说,根据用户的实际场景不同,可能对于数据库也有不同的要求,这个时候就需要对不同的数据库有支持,不能对于A数据库是支持的,对于B数据库的场景下,就出异常或者结果不正确了。

    需求分析

    由于要对程序员透明,因此解决方案不应该在DAO层实现。

    由于要和不同的用户权限系统进行集成,因此确定了不能在DAO层实现。

    对于分页有良好的支持,决定了不能在DAO层和显示层实现。

    一次设计到处生效,对多种ORMapping方案生效,决定了不能在ORMapping层实现。

    要求能跨数据库,进一步提升了方案的通用性和普适性,也提升了实现的难度。

    数据行权限不是所有的过滤条件都是和用户、角色、岗位字段有关的,不是所有的表中,都有用户、角色、岗位字段,这个时候也要能良好支持。比如:人员信息表中:不同的级别的HR,可以看到不同级别的人员信息。总之过滤条件可能是数据表中的任意字段。

    数据列权限是控制列的可见性的,也就是说,同样对这行数据有权限,但是可能对其中的几列没有权限,则这几列不可见。

     

    比如表table1 有(a,b,c,d,e,f)字段,列权限控制可能控制c,d不可见。但是程序员写代码的时候可能写的是select * from table1,这种情况下也不能返回c,d字段。

    实现思路

    呵呵,估计现在已经把许多方案已经逼到垃圾堆了。说实际关于这个主题,我也思考了相当长的时间,一直没有好的解决办法。因为我自己给出了N个解决方案,又都被自己所推翻,因为这些方案距离我期望的方案都有相当的距离。

    直到有一天,开一个无聊的会,然后就走神了,忽然之间冒出一个想法,然后仔细品味一下,貌似可以讲通,于是和开发人员进行了一下推演,技术实现上没有什么问题, 那就先做一版出来再说。

    下面简单说一下思路,真正的实现思路将在真正实现之后再行补充。

    归根到底,数据权限的实现思路就是个调整SQL的问题,直白点就是做加减法的问题。

    对于行权限来说无非是把一部分SQL条件附加到程序员写的SQL语句中,对于列权限来说则是把程序员写的SQL语句一部分从SQL里减去的问题。

    然后问题就转化为在哪一层里对程序员的SQL进行处理的问题,由于上面在提需求的时候附加了一系列的条件,因此也就确定了这一层不可能在DAO层,也不可能在ORMapping层来解决,这个时候可以添加层次就和分库分表方案一样了,只能在JDBC层或者协议代理层来解决,相对来说协议代理层离得太远了,因此在JDBC层就是一个合适的选项。

    上面一段说离得太远,是指在应用中,这些 SQL的加减需要根据当前登录人员的身份进行判定,在代理层要获得当前登录人员的信息会非常复杂,因此会增加额外的复杂度,确实是离得太远。但是在JDBC层做起来就方便多了。

    在JDBC层来进行处理,有几个好处,第一:所有的SQL语言,不论用得什么ORMapping方案,最后总是绕不过这一层的;第二、这一层实现的话,对于开发人员来说是全透明的;第三、这一次离业务实现足够近,可以比较方便的获得当前登录用户的相关信息。

    故事讲到这里,整个实现方案已经没有什么悬念了:通过在JDBC层对要处理的SQL语言进行解析,然后根据定义好的数据权限规则对SQL进行处理,通过增减SQL片断,使之达成数据权限控制的目的。

    总结

    通过上面对问题的分析,需求的整理,需求的分析及设计思路的思考,我就对数据权限的来龙去脉及其解决方案进行了比较深入的分析,亲们可以根据我的思路自行实现,也可以期待我们实现。

    转载于:https://www.cnblogs.com/shej123/p/10721428.html

    展开全文
  • 小编我不怎么善于文字表达,具体看如下图  

     小编我不怎么善于文字表达,具体看如下图

     

    展开全文
  • 现在有一个问题就是,我对一个角色设置完权限之后,在这个中会生成多条数据。而如果去修改这个角色的权限的话。要怎么去修改。现在我是把以前的数据全部删除,然后再添加数据。但我感觉数据库操作太繁琐。 各位...
  • 设计管理系统的权限模块,其中权限分为菜单访问权限数据(按钮)操作权限,按照上个系统的设计模式,有角色和用户,用户绑定角色,而角色可以绑定权限集合,用户也可以绑定权限集合,然后在用户登录的时候取...
  • 资源:这里指的资源是广义上的资源,包括很多的东东,模块、数据,菜单、节点、按钮、控件,、字段、存储过程,页面、窗口、表单、图表、报表,什么都可以算作是一种资源。您也可以把您遇到的一些情况都来算作是一...
  • 基于权限基础建立,权限基础数据操作。 简单叙述下流程: 登录账号:获取当前账号绑定的role,根据role获取此role关联的action,action为菜单的时候怎么做,为按钮的时候怎么做。 此处介绍一种最简单的方法仅供...

    基于权限基础表建立,权限基础数据操作。

    简单叙述下流程:

    登录账号:获取当前账号绑定的role,根据role获取此role关联的action,action为菜单的时候怎么做,为按钮的时候怎么做。

    此处介绍一种最简单的方法仅供参考。

    第一步 登录

    流程:

    前台:

    1.发送账号密码到action(各种验证不再讲述)

    actiong层

    1.根据账号密码进行查询

    2.获取role 保存到session

    3.获取action 保存到session

    4.登录失败提示

    public String login() {
            String r = "";
    
            T_user u = service.getByHql("from T_user where t_name='"
                    + data.getT_name() + "'and t_password='" + data.getT_password()
                    + "'");
            if (u != null) {
                Set<T_role> roles = u.getRole();
                for (Iterator<T_role> iterator = roles.iterator(); iterator
                        .hasNext();) {
                    T_role role = iterator.next();
                    getSession().setAttribute("role", role.getName());
                    getSession().setAttribute("roleid", role.getId());
                    Set<Menu> menu = role.getMenu();
                    List<Menu> list = new ArrayList<Menu>(menu);
                    getSession().setAttribute("action", list);
                }
                r = "login";
            } else {
                r = "loginOut";
            }
            return r;
        }

    这样的话就将所有action保存了到了session中(此处没有加按钮,以后会做一份优化的,此时没有时间)

    然后权限菜单树根据角色生成不同的菜单

    前台

    1.easyui异步树

    action层

    1.获取角色Id

    2.根绝角色id查关联节点

    3.生成异步树

    //获取当前角色的权限树
        public void getRoleTree()
        {
            
            String  roleId=(String) getSession().getAttribute("roleid");
            JSONArray jsonArray =new JSONArray();
            
            String hql="";
            try {
                if(id!=null&&!id.equals(""))
                {
                    hql="From Menu Where pid='"+id+"'";
                    
                }
                else
                {
                    hql="From Menu Where pid=NULL";
                }
                    
                List<Menu> list=service.find(hql);
                    
                for(int i=0;i<list.size();i++)
                {
                    Set<T_role> role =new HashSet<>();
                    role=list.get(i).getRole();
                    JSONObject json=new JSONObject();
                
                    for (Iterator<T_role> iterator = role.iterator(); iterator.hasNext();) {
                        T_role r = iterator.next();
                        if(r.getId().equals(roleId))
                        {
                            
                            json.put("id", list.get(i).getId());
                            json.put("text",list.get(i).getName());
                            if(service.find("From Menu Where pid='"+list.get(i).getId()+"'").size()==0)
                            {
                                json.put("state","open");
                            }
                            else if(service.find("From Menu Where pid='"+list.get(i).getId()+"'").size()>0)
                            {
                                json.put("state","closed");
                            }
                            JSONObject j=new JSONObject();
                            j.put("url",list.get(i).getUrl());
                            json.put("attributes",j);
                            jsonArray.add(json);
                            
                        }
                        
                        }
                    }
                    
            } catch (Exception e) {
                // TODO: handle exception
                
                logger.info(e.toString());
            }
            writeJson(jsonArray);
        }

    对于按钮保存到session的思路为再

    getSession().setAttribute("quanxian", "none");在session中保存对应按钮的标识为显示或隐藏

    按钮上style="disply:${sessionScope.quanxian}"

    这样的话就将对应的按钮隐藏了。当然后面有更好的方法先写到这里,后面会有更好的方法。

    转载于:https://www.cnblogs.com/wsy123/p/4463086.html

    展开全文
  • 问题:系统有多用户,用户可以拥有不止一个角色(又称身份、...按照标准的数据建模原则,应该建立如下的,表示三种数据实体:用户、角色以及权限 CREATE TABLE User ( id INTEGER, name VARCHAR(16), CONSTRAI
  • 问题:系统有多用户,用户可以拥有不止一个角色(又称身份...按照标准的数据建模原则,应该建立如下的,表示三种数据实体:用户、角色以及权限 CREATE TABLE User ( id INTEGER, name VARCHAR(16), CONSTRAI...
  • 权限系统的涉及到的数据表结构如下: 很简单,有图在此一目了然。一个角色对应多个功能,而每个功能又包含很多子功能,所以在设计的时候考虑要用到这5张表。在进行开发之前需要安装和配置TreeView控件,如果不...
  • 权限系统的涉及到的数据表结构如下: 很简单,有图在此一目了然。一个角色对应多个功能,而每个功能又包含很多子功能,所以在设计的时候考虑要用到这5张表。在进行开发之前需要安装和配置TreeView控件,如果不...
  • 建设期(数仓分层、主题域划分、权限设计数据字典、任务等级) 成熟期(维度建模VS宽、重新设计DW分层、命名规范、计算引擎进化) 三、有赞数仓还在进化 消除重复计算 数仓的价值 原文地址:戳↓ ...

空空如也

空空如也

1 2 3 4 5 ... 11
收藏数 218
精华内容 87
关键字:

数据权限表怎么设计