博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
如何完成一个严谨的权限管理系统
阅读量:4221 次
发布时间:2019-05-26

本文共 5850 字,大约阅读时间需要 19 分钟。

背景介绍:

在后台管理中,经常要涉及到权限的管理,比如:某个用户可以访问某个菜单,禁止访问某个菜单。常见的处理方式有两种:

(1)直接将用户与权限相管理;

(2)将用户与角色关联,角色与权限关联(即基于角色的权限控制RBAC,Role Based Access Control)

第二种方式,显然更灵活,权限与角色关联,而用户只与角色关联,这样同一个角色可以对应多个用户。

完整的权限系统必须至少具备以下两点:

(1)禁止越权访问页面。举个栗子:在工作遇到某些后台,表面上对于某些用户不能见到某些页面,但是如果用户通过URL则仍然可以访问该页面,因此,该漏洞使得用户仍然可以越权访问不应该访问的页面。

(2)控制接口请求响应的数据。举个栗子:在工作中后台中对于接口请求响应(如:Json数据),并没有做控制。该漏洞使得任何能够成功登录该系统的用户,只要知道该接口地址即可获取请求响应数据。

一个可用的Demo案例如下:

1、创建表结构:

用户表:

create table tb_user_center(	id int unsigned not null auto_increment comment '主键',	name varchar(255) not null default '' comment '用户姓名',	sex char(4) not null default '' comment '用户性别:男-boy;女-girl;缺省为空,性别未填写',	address varchar(255) not null default '' comment '用户地址',	note text not null comment '备注',	mtime int unsigned not null comment '更改时间',	ctime int unsigned not null comment '创建时间',	primary key(id))engine innodb default charset utf8 comment '用户信息表';

插入数据:

insert into tb_user_center(id, name, sex, role_id, address, note, mtime, ctime)values(1, 'tim', 'girl', 1, '福建','我是超级超级管理员,适合所有权限',1500778973, 1500778973);insert into tb_user_center(id, name, sex, role_id, address, note, mtime, ctime)values(2, 'feier', 'girl', 2, '泉州','普通管理员权限',1500778973, 1500778973);

 

角色表:

create table tb_role(	id int unsigned not null auto_increment comment '主键id',	name varchar(255) not null comment '角色名称',	status tinyint unsigned default 0 not null comment '状态:0禁用;1启用',	note text not null comment '备注',	mtime int unsigned not null comment '更改时间',	ctime int unsigned not null comment '创建时间',	primary key(id))engine innodb default charset=utf8 collate utf8_general_ci comment '角色表';

插入数据:

insert into tb_role(name, status, note, mtime, ctime)values('管理员',1,'备注',1500778399, 1500778399);insert into tb_role(name, status, note, mtime, ctime)values('运营人员',1,'备注',1500778399,1500778399);

 

角色对应的权限表:

create table tb_role_auth(	id int unsigned not null auto_increment comment '主键id',	role_id int unsigned not null comment '角色id',	action text not null comment '权限列表[以英文逗号分隔各个角色]',	mtime int unsigned not null comment '更改时间',	ctime int unsigned not null comment '创建时间',	primary key(id),	unique index role_id_index(role_id))engine innodb default charset=utf8 comment '角色对应的权限表';

插入数据:

insert into tb_role_auth(role_id, action, mtime, ctime)values(1,'Home, userStat,dataAna',1500779576,1500779576);insert into tb_role_auth(role_id, action, mtime, ctime)values(2,' userStat,dataAna',1500779576,1500779576);

2、示例代码

这里给出一个用户统计相关的代码,将页面和api请求接口单独出一个类,具体写法参考我的博客:。首先贴出页面和api接口的代码如下:

(1)统计页面相关的控制器类如下:

@Controller@RequestMapping("/userStat")public class UserStatPageController {    private static final Map
_perm = new HashMap
(); private static final int UID = 2;//这个是用户id,不同用户id不一样 static{ _perm.put("/userStat/listAll.do", "userStat"); _perm.put("/userStat/addPage.do", "userStat"); } @Autowired private JdbcTemplate jdbcTemplate; @RequestMapping("/listAll") public String listAll(HttpServletRequest request){ //鉴权操作 this.checkPerm(request); return null; } /** * 鉴权函数 * @date 2017年7月23日 */ private void checkPerm(HttpServletRequest request){ if(1 == UID){ //UID = 1,表示是超级用户,即数据库第一个添加的用户 return ; } String uri = request.getRequestURI(); String action = this._perm.get(uri); //注意:这里为了简单将sql用拼接(可能会被注入,项目中应该改为预编译) String sql = "select action from tb_user_center uc left join tb_role_auth ra on uc.role_id=ra.role_id where uc.id=" + UID + ";"; String actions = jdbcTemplate.queryForObject(sql, String.class); String[] actionsArr = actions.split(","); if(Arrays.asList(actionsArr).contains(action)){ System.err.println("恭喜您拥有该权限"); }else{ System.err.println("对不起,当前权限受限"); } }}

(2)与统计接口请求相关的控制类

@Controller@RequestMapping("/userStat")public class UserStatApiController {    private static final Map
_perm = new HashMap
(); private static final int UID = 2; //这个是用户id,不同用户id不一样 static{ _perm.put("/userStat/add.do", "userStat"); _perm.put("/userStat/update.do", "userStat"); } @Autowired private JdbcTemplate jdbcTemplate; @RequestMapping("/add") public String add(HttpServletRequest request){ //鉴权操作 this.checkPerm(request); return null; } /** * 鉴权函数 * @date 2017年7月23日 */ private void checkPerm(HttpServletRequest request){ if(1 == UID){ //UID = 1,表示是超级用户 return ; } String uri = request.getRequestURI(); String action = this._perm.get(uri); //注意:这里为了简单将sql用拼接(可能会被注入,项目中应该改为预编译) String sql = "select action from tb_user_center uc left join tb_role_auth ra on uc.role_id=ra.role_id where uc.id=" + UID + ";"; String actions = jdbcTemplate.queryForObject(sql, String.class); String[] actionsArr = actions.split(","); if(Arrays.asList(actionsArr).contains(action)){ System.err.println("恭喜您拥有该权限"); }else{ System.err.println("对不起,当前权限受限"); } }}

分析:

这里对于每个页面请求或者api请求的uri,都通过对应类的map进行静态map控制,比如对于接口api的请求:

private static final Map
_perm = new HashMap
(); static{ _perm.put("/userStat/add.do", "userStat"); _perm.put("/userStat/update.do", "userStat"); }

当执行添加操作,发起的请求uri是”/userStat/add.do”,而该权限是属于模块“userStat”,关于权限的表中的数据如下:

可以看到对于角色1和2都拥有userStat模块的权限。

因此,我们只需根据用户UID去查询该用户对应的权限模块,sql语句如下:

String sql = "select action from tb_user_center uc left join tb_role_auth ra on uc.role_id=ra.role_id where uc.id=" + UID + ";";

最后,只需判断返回的权限列表中是否包含this._perm.get(uri);对应的值。

补充一点:
if(1 == UID){ //UID = 1,表示是超级用户            return ;        }

在权限校验中,对于UID为1的用户,可以不用对其进行权限校验,因为这是超级用户,即我们系统的第一个用户,此时系统中所有权限表都还是空的,都需要该用户来通过页面进行创建的。

你可能感兴趣的文章
lua学习笔记之五(Lua中的数学库)
查看>>
【屌丝程序的口才逆袭演讲稿50篇】第一篇:互联网时代U盘化生存方式 【张振华.Jack】
查看>>
CentOS6.4配置Hadoop-2.6.0集群配置安装指南(经过实战演练)【张振华.Jack】
查看>>
【屌丝程序的口才逆袭演讲稿50篇】第二篇:专注的力量 [张振华.Jack]
查看>>
【屌丝程序的口才逆袭演讲稿50篇】第三篇:我的舍与得的2014[张振华.Jack]
查看>>
【屌丝程序的口才逆袭演讲稿50篇】第五篇:不要给自己找任何借口【张振华.Jack】
查看>>
【屌丝程序的口才逆袭演讲稿50篇】第七篇:请留意我们身边的风景 【张振华.Jack】
查看>>
【屌丝程序的口才逆袭演讲稿50篇】第八篇:坚持的力量 【张振华.Jack】
查看>>
【屌丝程序的口才逆袭演讲稿50篇】第九篇:春节那些事-过年回家不需要理由【张振华.Jack】
查看>>
【屌丝程序的口才逆袭演讲稿50篇】第十一篇:马云乌镇40分钟演讲实录【张振华.Jack】
查看>>
Java并发编程从入门到精通 张振华.Jack --我的书
查看>>
【屌丝程序的口才逆袭演讲稿50篇】第十二篇:世界上最快的捷径【张振华.Jack】
查看>>
Android中Java代码和XML布局效率问题
查看>>
android TextView属性大全(转)
查看>>
Conclusion for Resource Management
查看>>
Conclusion for Constructors,Destructors,and Assignment Operators
查看>>
《浪潮之巅》1 AT&T
查看>>
《浪潮之巅》2蓝色巨人 IBM公司
查看>>
《浪潮之巅》3水果公司的复兴
查看>>
《浪潮之巅》4计算机工业的生态链
查看>>