RBAC基于角色的权限管理--设计篇1.0
RBAC是什么
基于角色的权限管理。简单来说就是一个用户可以拥有若干个角色,一个角色可以拥有若干个权限。这样就形成了“用户-角色-权限”的模型。
基础表设计
- 数据库采用MySql
- 这里表设计只采用最基础的字段
- 忽略字段长度,如采用此设计,请自行修改
- 忽略外键建设,如采用此设计,请自行建立
用户表
CREATE TABLE `t_user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`create_user` datetime DEFAULT NULL COMMENT '创建人',
`login_time` datetime DEFAULT NULL COMMENT '登录时间',
`name` varchar(255) DEFAULT NULL COMMENT '用户名称',
`password` varchar(255) DEFAULT NULL COMMENT '登录密码',
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
`status` int(11) DEFAULT NULL COMMENT '用户状态',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`update_user` datetime DEFAULT NULL COMMENT '更新人员',
`username` varchar(255) DEFAULT NULL COMMENT '登录名称',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
角色表
CREATE TABLE `t_role` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '角色id',<br/>
`role_name` varchar(255) DEFAULT NULL COMMENT '角色名称',
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
权限表
CREATE TABLE `t_permission` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '权限ID',
`permission_code` varchar(255) DEFAULT NULL COMMENT '权限编码',
`permission_name` varchar(255) DEFAULT NULL COMMENT '权限名称',
`pid` int(11) DEFAULT NULL COMMENT '父类权限ID(依赖权限)',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
用户角色关系表
CREATE TABLE `t_user_role` (
`user_id` int(11) NOT NULL COMMENT '用户id',
`role_id` int(11) NOT NULL COMMENT '角色id',
PRIMARY KEY (`user_id`,`role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
角色权限关系表
CREATE TABLE `t_role_permission` (
`role_id` int(11) NOT NULL COMMENT '角色id',
`permission_id` int(11) NOT NULL COMMENT '权限id',
PRIMARY KEY (`role_id`,`permission_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
权限控制
控制菜单
场景
管理员和普通会员。如管理员可以看到所有菜单,普通会员只能看到一部分菜单(或可以看到,但点击时弹出没有权限操作的提示。由于个人喜好和个人体验度偏差的原因,此文章中不采取这种方式)。
问题来了,如何控制角色的菜单权限?let‘s go!!!
表设计
CREATE TABLE `t_menu` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`menu_name` varchar(255) DEFAULT NULL COMMENT '菜单名称',
`permission_code` varchar(255) DEFAULT NULL COMMENT '权限编码(菜单编码)',
`pid` int(11) DEFAULT NULL COMMENT '父菜单id',
`url` varchar(255) DEFAULT NULL COMMENT '菜单url跳转链接',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
简要业务流程图
详细业务流程图
控制按钮
场景
拥有了菜单权限,依旧不能满足某些场景的需要。例如多个角色在同时拥有A菜单的情况下,角色1可以有查询,创建的权限,角色2则拥有查询,创建,修改,删除的权限。即角色1只能看到查询,创建的按钮,角色2可以看到查询,创建,修改,删除的按钮。这个时候,我们应该如何处理呢?
实现
- 按钮权限定义:在菜单权限下定义下级权限查询,创建,修改,删除,例如Aquery,Aadd,Aupdate,Adelete。
- 这里结合shiro使用(不会使用的小伙伴请留言,后期补上解决方式):在A菜单跳转的页面中使用shiro:hasPermission则可以达到控制按钮的效果。例如
<shiro:hasPermission name="Aadd">
<button>新建<button>
</shiro:hasPermission>
详细业务流程图(结合shiro)
代码示例(思想很重要)
检查用户是否有菜单权限
/**
* 检查用户是否有菜单权限
*
* @param menus
* 所有菜单
* @param subject
* shiro用户信息
* @return 用户已分配的菜单集合
*/
private List<Menu> check(List<Menu> menus, Subject subject) {
List<Menu> res = new ArrayList<Menu>();
for (Menu m1 : menus) {
if (StringUtils.isEmpty(m1.getPermissionCode())) {
continue;
}
// 这里会触发鉴权操作
if (subject.isPermitted(m1.getPermissionCode())) {
res.add(m1);
}
}
return res;
}
自定义realm-鉴权操作
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// 查询当前用户所有权限
List<Permission> infos = userService.findMyPermitions();
// 权限集合(这里我习惯把权限编码放进去)
Set<String> permissions = new HashSet<String>();
// 角色集合(这里放角色ID)
Set<String> roles = new HashSet<String>();
if (infos != null && infos.size() > 0) {
for (Permission info : infos) {
permissions.add(info.getPermissionCode());
roles.add(info.getRoleId());
}
}
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.setStringPermissions(permissions);
authorizationInfo.setRoles(roles);
return authorizationInfo;
}
数据权限
场景
有些业务可能会是这样。一个列表(或表格),要求普通用户只能看到自己创建的列表信息,业务部门经理只能看到本部门的所有列表信息。这种权限如何控制?
实现
看反应,下回见。