权限管理系统中的根据用户角色动态生成用户权限菜单树

来源:互联网 发布:max软件是什么 编辑:程序博客网 时间:2024/06/08 02:43

  权限管理系统中的根据用户角色动态生成用户权限菜单树



       暑假在工作室学习了基于RBAC的权限管理系统,学的比较浅显,记录下方便以后学习可以看。

        一、首先讲讲我对RBAC的理解

             关系:用户->角色->权限。
             可以看到角色是在中间的,所以说是基于角色的。
             1.1说说用户和角色的关系
             首先假设我们每个人都有一个CSDN账号,那么现在我们就都是CSDN网站的用户了是吧,用户有了,接下来解决关系链中的角色问题:我们都知道VIP概念是吧,我们注册了CSDN账号,就是拥有普通用户身份(角色),这个时候我们要去下载CSDN网站上面的资源(代码大笑),可能就要积分了,因为你只是普通用户,然后你感觉不爽麻烦,充钱买了CSDN会员,这个时候下载就免积分了(爽微笑),那CSDN是怎么判断你是会员的呢(if(user.equals(“会员”)大笑),开玩笑的微笑
              问个问题,冲了会员后你有几个身份?(身份=角色)
              答案是两个:普通用户+会员用户,也就是说普通用户可以做的东西(比如写博客)你也能做,会员可以做的你也有权利(比如免积分下载资源),说了这么多只是想说明用户可以拥有多个角色。 

             1.2说说角色和权限的关系
              上面说到你现在是会员了(牛批牛批微笑),会员就可以为所欲为了嘛,我们冲过微博会员什么的就知道,冲了会员就应该让别人知道老子是会员(不然冲来干嘛,肯定要装一下逼啊,不然人生多无趣微笑),好了会员可以换皮肤,让你头像发出金色光芒(24K),免积分下载这么多功能,这是普通会员没有的(他们只能写博客再见),所以一个角色(这里是会员,当然普通用户也是一个角色)拥有了多个权限。
             1.3把用户和权限对应起来
             你是会员,CSDN是怎么知道的呢,总不能是设置level=0(普通),level=1(会员),if(level==0)if(level==1)这样来吧,这样系统大点就累死你,显然行不通,我们回到RBAC,用户->角色->权限,这个关系链上面来,合理的做法是我们会给用户分配多个不同的角色,在这里比如冲会员,就是分一个会员的角色给你了嘛(你牛批),然后每个角色都拥有不同的权限,我们拥有了角色,就可以拥有角色下面的权限,比如你会员嘛,那你就有换皮肤、免积分下载的权限了嘛,原理就是用户登录了,通过检索出用户拥有的角色(你是普通用户和会员),再通过这些角色检索出角色拥有的权限(普通用户:写博客;会员:换皮肤,下载免积分),这样就得到了用户拥有的权限(写博客,换皮肤,下载免积分),也是RBAC的基本原理,基于角色的。

      二、取出用户权限菜单树

      上面讲到用户->角色->权限,其实我们作为管理员,要想在后台动态分配菜单给用户,还需要一个叫资源的东西,Resource,不管你怎么叫,这个资源也是我们用户可以看到的菜单,也就是可以点的链接,这个菜单是管理员分配给我们的,我们看下实现图

                        
        
         右边两个箭头就是所谓的分配菜单,管理员分配给你了这个菜单(权限),你登录之后才能看得到对应的菜单,不然你一点权限都没有,也就看不到功能菜单了,也就是左边箭头的菜单。我们作为开发者,也就是后台的超级管理员,为了方便我们操作,也就是和上图一样,打个勾就是给角色分配权限了(前端用户看到的菜单),我们就需要
Resource(资源),也就是图中的一条条菜单选项。
         那么问题来了,上图中右边的都是权限(资源),既是分配权限,又是分配资源,
我们就要把权限和资源关联起来,可以使用关联表或者外键,这样我们就可以通过资源,看到所谓的权限了,所以资源是为了让我们方便实现,操作权限。

        为了加深理解我们再看看资源的设计
        
       如图,我们可以看到每个小资源对应每个URL
       问题来了,权限和资源的关系呢,回答前我想问下,什么是权限呢
       举个栗子,就是比如你进入一个界面,里面有几个按钮,添加,删除,更改,查询
       这些按钮就是你的权限了,可是这些按钮都在一个页面上面(对应某个URL),
       所以很明确了,一个资源对应多个权限,资源只是方便我们实现了操作,可以说权限和缥缈虚无,我们看不到,那么就用资源(一个个菜单链接)来代替,使用户可以看到操作.
      
      一个资源对应多个权限,我们看下图
      

       可以看到,一个资源(菜单链接)对应多个权限。

      最后,整理思路,用户登录之后,我们检索用户拥有的角色,再根据角色检索出权限(这些我们可以用中间表来对应关系,方便检索),这个时候我们就检索出了用户的所有权限,是时候动态生成菜单树了,拥有了权限,还需要检索出对应的资源,同样我们可以用中间表或者外键实现。
     我贴一段生成资源树的代码。它的思路就是把资源树的节点全部检索出来,并且检索出每个节点的子节点,这样我们实现Resource.getSub就可以知道这个节点下面还有哪些菜单选项了,最后返回第二层的所有父节点给前端,我们就可以从上往下递归生成所有的菜单链接。
   后端代码
   
    /**     * 生成用户的资源权限的树结构     * @return     * @throws Exception     */    public List getUserPermTree(User currentUser)throws Exception{        log.info("===生成用户的资源权限的树结构===");        List result = new ArrayList<>();        //权限数据预处理        Map> permMap = new HashMap<>(50);        List roles=userMapper.getRoles(currentUser.getId());//获取用户所有角色        List perms=new ArrayList<>();//获取用户所有权限        for(Role role:roles){            List temp=permissionMapper.listByRole(role.getId());            perms.addAll(temp);        }        perms.forEach(p -> {            if(!permMap.containsKey(p.getResid()))                permMap.put(p.getResid(), new ArrayList<>());            permMap.get(p.getResid()).add(p);        });        //资源数据处理        Map resourceMap = new TreeMap<>();        Set rids=new HashSet<>();        for(Permission permission:perms){//根据权限获取资源id列表            rids.add(permission.getResid());        }        CopyOnWriteArrayList resources=resourceMapper.listByids(rids);        for(Resource resource:resources){            getFRes(resource,resources);//寻找资源的父节点(菜单头)        }        resources.forEach(r -> {            //将权限与资源关联起来            if(permMap.containsKey(r.getId())){                r.setPerms(permMap.get(r.getId()));            }            //清除缓存带来的影响            r.getSub().clear();            resourceMap.put(r.getId(), r);            if(r.getPid() == null || r.getPid() == 1){                result.add(r);            }        });        //再一次循环构建资源的父子关系        resources.forEach(r -> {            if(r.getPid() != null  && resourceMap.containsKey(r.getPid())){                Resource resource = resourceMap.get(r.getPid());                resource.getSub().add(r);            }        });        return result;    }    private void getFRes(Resource resource,List resources){        if(resource.getPid()!=null||resource.getPid()!=1){            Resource father=resourceMapper.selectByPrimaryKey(resource.getPid());            if(father!=null&&!father.getName().equals("root")){                if(!resources.contains(father)){                    resources.add(father);                }                getFRes(father,resources);            }else{                return;            }        }else{            return;        }    }

  前端代码(我这里用的是easyui前端框架)

              
  • ${subMenu.name}
  • ${subMenu.name}
    • ${sub.name}

  最后,我qq是1807768141,有问题可以评论或者加我QQ大笑
       

阅读全文
1 0
原创粉丝点击