JavaWeb-权限管理

来源:互联网 发布:网络信息安全重大事件 编辑:程序博客网 时间:2024/05/21 10:55

最近看公司的代码,对权限管理颇有兴趣,恰好今天有空,就记录了以下,如果有错误,还望指正

正统表结构:

图片摘自慕课

从图上可以看出,表结构主要有User Role Function 三个表,分别对应用户、角色、功能,通过这三张表完成权限的控制和实现。

User 与 Role 是多对多关系,使用第三方UserRole表来维护
Role 与 Function 同样也是多对多的关系,多个角色对应多个功能(每个模块都有对应的id,功能即模块,即menu),使用第三方表RoleFunction来维护

大概思路:

用户登陆时加载菜单,根据用户查询用户角色,根据用户角色查询用户功能,将查询到一个menu code,然后返回这些menu code

在控制层在根据menu code 获取并加载菜单

但是无法对每个menu 中的按钮权限进行控制(比如添加、删除、审核)

解决办法:在Role和Function的第三方表中插入一列:menu_btn,代表该该角色下的功能拥有什么样的按钮权限

然后查询时,封装一个拥有menu_btn的实体类menu,用来记录权限,如果没有任何button,则不显示任何菜单


项目做法:

表结构:

T_SYS_USER 用户表

T_SYS_ROLE 角色表

T_SYS_USER_ROLE 用户角色关系表

T_SYS_MENU 功能表

T_SYS_ROLE_PRIVILEGE 按钮权限

[关于权限按钮列表]:

系统有固化的权限按钮,新增,修改,删除,查看,审核..

名称对应:ADD_BTN,MOD_BTN,DEL_BTN,VIEW_BTN,AUDIT_BTN…应:ADD_BTN,MOD_BTN,DEL_BTN,VIEW_BTN,AUDIT_BTN…

多个用户对应多个角色 , 使用第三方表T_SYS_USER_ROLE维护


权限管理中的授权问题:

一个用户可以对应多个角色,A角色的操作权限和B角色的操作权限有冲突,那该以谁的为准?

下面有几种解决方案:

  1. 合并权限,将A角色的权限和B角色的权限合并 √
  2. 在视图上给用户选择,让用户可以切换角色,操作麻烦 ×
  3. 如果角色之间有授权冲突,则不允许授权 ×
  4. 允许用户对冲突角色进行授予,让用户在授予权限时,设置角色的优先级,当角色冲突时,以优先级高的角色为准 √

公司代码分析:

    // 定义一个map,用来保存菜单权限     Map<String, MenuPrivilege> ret = new HashMap<String, MenuPrivilege>();    // 查询出权限并添加,使用sql直接查询menu,不查role,即不实例化role,即可避免这个问题,但是btns又拥有这个问题,待解决    List<SysRolePrivilege> priviletList = sysRolePrivilegeDao.findByUserRolePrivilege(userId);    for (SysRolePrivilege rp : priviletList) {        ret.put(rp.getMenuCode(), new MenuPrivilege(rp.getMenuCode(), rp.getMenuBtn()));      // 相同的menu code会直接被map的唯一性覆盖    }    return ret;

问题解决,思路大概是按照解决方案一

新问题: btns问题

A role 对应 A menu - btn_add, btn_query

B role 对应 A menu - btn_add, btn_delete

如果Arole和Brole都赋给User1那么权限以谁的为准?

// todo 貌似是公司代码bug,待考证


代码展示:

项目的权限管理是根据当前用户的类型,决定要显示的菜单 从而实现权限管理的功能

当加载menu时,会在控制层根据当前登陆用户获取菜单:

    /* 功能菜单数据获取 */    @RequestMapping("tree")    @ResponseBody    public Object menuTree(HttpServletRequest request, HttpSession session) {      ...      // 从数据库中获取菜单数据      List<SysMenu> list = menuService.menusOfUser(session);      List<Map<String, String>> ret = new ArrayList<Map<String, String>>();      for (SysMenu po : list) {        Map<String, String> map = new HashMap<String, String>();        map.put("id", po.getMenuCode());        map.put("pid", po.getMenuPcode());        map.put("name", po.getMenuName());        if (po.isLeafYn()) { // 如果为叶子节点          map.put("url", "menu/jump/" + po.getMenuCode()); // 点击链接        } else {          map.put("url", po.getMenuUrl());        }        ret.add(map);      }      return ret;   // 这里在mvc配置文件中配置了json转换器,spring mvc会自动帮你将集合转换为json字符串,发送给jsp,使用js进行菜单的显示    }
List<SysMenu> list = menuService.menusOfUser(session);

menusOfUser方法:

    @Service("menuService")     public class MenuService {        public List<SysMenu> menusOfUser(HttpSession session) {          SessionUser sessionUser = (SessionUser) session.getAttribute(SessionUser.SESSION_USER_KEY);          Assert.notNull(sessionUser, "user information in session cannot be null");          // 超级管理员          if (SysUser.USER_TYPE_MASTER == sessionUser.getUserType()) {              return menuList;          }          // 其他普通用户          Map<String, MenuPrivilege> menus = sessionUser.getPrivilege();          // 如果没有权限菜单,返回空          if (menus == null || menus.size() == 0) {              return new ArrayList<SysMenu>();          }          List<SysMenu> result = new ArrayList<SysMenu>();          for (SysMenu sysMenu : menuList) {              if (menus.containsKey(sysMenu.getMenuCode())) {                  result.add(sysMenu);              }          }          return result;      }    }
原创粉丝点击