1. 程式人生 > >【基於角色的訪問控制RBAC】許可權與資源樹

【基於角色的訪問控制RBAC】許可權與資源樹

基於角色的許可權訪問控制(Role-BasedAccess Control)。在RBAC中,許可權與角色相關聯,通過使使用者成為適當的角色而得到這些角色的許可權。使用者可以很容易地從一個角色被指派到另一個角色。角色可依新的需求和系統的合併而賦予新的許可權,而許可權也可根據需要而從某角色中回收。這就極大地簡化了許可權的管理。


資源樹將整個系統的功能按模組劃分,如使用者管理模組,檔案管理模組,使用者管理模組下又有管理員管理,工作單位管理,系統使用者管理等。而每一個資源模組下面,都可能有多個許可權需要控制,比如工作單位管理,至少要有最基本的檢視,修改,增加,刪除四個功能,為了讓特定的角色擁有特定的功能,我們需要對功能設定許可權,因此工作單位管理模組至少需要有以下許可權:檢視工作單位,修改工作單位,刪除工作單位,新增工作單位。因此資源與許可權的關係為:一個資源擁有多個許可權

。為了在後臺方便程式設計人員控制權限,每個許可權都會有一個許可權編碼。通常相同資源下用相同的字首來表示,比如上面那個可以用work:list,work:add,work:delete,work:edit

 


資源樹構建過程:

先獲取當前使用者的所有角色,從而得到使用者的所有許可權。根據許可權獲得資源resourceId列表,通過resourceId將使用者擁有的資源樹利用組合模式組合起來,傳給前端,由前端進行解析生成檢視。

 

後端程式碼如下:

/**
 * 生成使用者的資源許可權的樹結構
 * @return
 * @throws Exception
 */
public List<Resource> getUserPermTree(User currentUser)throws Exception{
    log.info("===生成使用者的資源許可權的樹結構===");
    List<Resource> result = new ArrayList<>();
    //許可權資料預處理
    Map<Long, List<Permission>>permMap = new HashMap<>(50);
    List<Role> roles=userMapper.getRoles(currentUser.getId());//獲取使用者所有角色
    List<Permission> perms=new ArrayList<>();//獲取使用者所有許可權
    for(Role role:roles){
        List<Permission> temp=permissionMapper.listByRole(role.getId());
        perms.addAll(temp);
    }

    perms.forEach(p -> {
        if(!permMap.containsKey(p.getResid()))
            permMap.put(p.getResid(), newArrayList<>());
        permMap.get(p.getResid()).add(p);
    });


    //資源資料處理
    Map<Long, Resource> resourceMap= new TreeMap<>();
    Set<Long> rids=new HashSet<>();
    for(Permission permission:perms){//根據許可權獲取資源id列表
        rids.add(permission.getResid());
    }
    CopyOnWriteArrayList<Resource>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<Resource>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;
    }
}


前端jsp程式碼:

<c:forEach items="${menuList}"var="menu">
    <div title="${menu.name}"data-options="iconCls:'icon-application-cascade'"  style="padding:5px;" >
        <ul class="ui-side-tree">
            <c:forEach items="${menu.sub}"var="subMenu">
                <c:if test="${subMenu.sub.size()eq 0}">
                    <li><a href="${ctx}${subMenu.url}">${subMenu.name}</a></li>
                </c:if>
                <c:if test="${subMenu.sub.size()ne 0}">
                    <li>
                        <span>${subMenu.name}</span>
                        <ul>
                            <c:forEachitems="${subMenu.sub}" var="sub">
                                <li><ahref="${ctx}${sub.url}">${sub.name}</a></li>
                            </c:forEach>
                        </ul>
                    </li>
                </c:if>
            </c:forEach>
        </ul>
    </div>
</c:forEach>