本文档主要是简单描述下权限控制的主要部分。
主要分成5个部分。
包含 URI.java,PNode.java, PModule.java, PMenu.java 对象
URI: 字面意思,所有Controller的@RequestMapping的value都在此对象定义。
PNode: 定义最细粒度的权限控制节点,也能起到聚合控制的作用。
PModule: 定义模块和模块下拥有的多个PNode节点。
PMenu: 定义访问菜单。聚合PModule定义的模块到菜单下。初步形成有层级的访问菜单。
彼此关联:
依据PMenu的配置代码,生成树形菜单的数据结构。
public class Menu {
private int id; // 当前ID PMenu.ordinal() + 1;
private int pid = 0; // 父id PMenu.ordinal() + 1
private String name; // 菜单名称
private List<Module> moduleList = new ArrayList<>(); // 模块列表
private List<Menu> subList = new ArrayList<>(); // 子菜单列表
}
public class Module {
private final int id; // PModule.ordinal() + 100;
private final int pid; // Menu实例的id
private final String pname; // 模块的值、名称
private final String desc;
private final List<PNode> nodeList = new ArrayList<>(); // 节点列表
}
结合以上两数据对象,生成层级菜单(List<Menu>
),供权限配置。
前端的层级展示采用 jquery-treegrid .
List<Menu>
数据结构示例[{
"id": 1,
"pid": 0,
"name": "系统基本配置",
"moduleList": [{
"id": 101,
"pid": 1,
"pname": "privilege_role",
"desc": "角色管理配置",
"nodeList": ["MANAGER",
"NEW",
"GET",
"EDIT"]
},
{
"id": 102,
"pid": 1,
"pname": "privilege_user",
"desc": "用户管理配置",
"nodeList": ["MANAGER",
"NEW",
"GET",
"EDIT"]
}],
"subList": []
}]
- 模块的权限表示,这里采用 索引字符 表示法。"10000000"的权限字符串,表示只有模块的PNode.MANAGER节点的访问、操作权限。(PNode.index 即是索引)
- 权限表只有模块和模块的权限数据,没有菜单结构的数据。
所以需要通过权限的模块,倒序生成出用户的访问菜单,后面会涉及。
先看表数据:
表结构比较简单,只有模块名、角色拥有的权限。
表结构同样只有模块名、角色拥有的权限。不过此表数据分两种情况:
- role_id > 0:表示基于角色给用户配置了权限。用户的权限数据直接定位到角色的权限数据。
- role_id==0: 表示此表里
user_id
指定的,即是用户的权限数据。
- 生成:
读取用户权限表数据-->对照PModule的定义将权限的字符表示转化为节点值列表。- 控制: 见
MySecurityPrivilegeFilter
的实现。有在web.xml
配置此Filter。- 结构:
List<Map<String, List<String>>> // List<Map<PModule.pname, List<PNode.pname>>>
数据示例(json):
[{
"privilege_role": ["manager",
"new",
"get",
"edit"]
},
{
"privilege_user": ["manager",
"new"]
}]
基于用户的【访问控制的权限数据】(List<Map<String, List<String>>>
)进一步生成有结构的菜单(List<Menu>
)。
见 PrivilegeService
。用户登录成功时加载,仅加载一次,并加到Session属性。加载见: MyAuthenticationSuccessHandler
对象。
[{
"id": 1,
"pid": 0,
"name": "系统基本配置",
"moduleList": [{
"id": 101,
"pid": 1,
"pname": "privilege_role",
"desc": "角色管理配置",
"nodeList": ["MANAGER",
"NEW",
"GET",
"EDIT"]
},
{
"id": 102,
"pid": 1,
"pname": "privilege_user",
"desc": "用户管理配置",
"nodeList": ["MANAGER",
"NEW",
"GET",
"EDIT"]
}],
"subList": []
}]
基于用户的【访问控制的权限数据】(List<Map<String, List<String>>>
),
结合PMenu的菜单与子菜单定义,由模块值逆序找到模块、找到拥有此模块的菜单、继续找父菜单。生成用于访问的树形菜单(List<AccessMenu>
)。
AccessMenu:
public class AccessMenu {
private final String desc;
private final List<AccessModule> moduleList = new ArrayList<>();
private final List<AccessMenu> subMenuList = new ArrayList<>();
}
AccessModule:
public class AccessModule {
private final String desc;
private final String uri;
}
见 PrivilegeService.mineAccessMenu()
[{
"desc": "系统基本配置",
"moduleList": [{
"desc": "权限基础数据",
"uri": "/hs/privilege/manager"
},
{
"desc": "角色管理配置",
"uri": "/hs/privilege_role/manager"
},
{
"desc": "用户管理配置",
"uri": "/hs/privilege_user/manager"
}],
"subMenuList": [{
"desc": "测试2",
"moduleList": [{
"desc": "用户管理",
"uri": "/hs/user/manager"
}],
"subMenuList": []
}]
},
{
"desc": "测试",
"moduleList": [{
"desc": "用户管理配置",
"uri": "/hs/privilege_user/manager"
}],
"subMenuList": []
}]
其中 subMenuList 有值,现在暂时只支持一层子菜单。有需要再考虑完善。 上面数据的效果图: