Role-Based Access Control

RBAC

基于角色的访问控制 (Role-Based Access Control)

表设计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#创建后台管理员表
DROP TABLE IF EXISTS ugo_admin;
CREATE TABLE ugo_admin(
admin_id TINYINT UNSIGNED auto_increment PRIMARY KEY COMMENT '管理员id' ,
admin_name VARCHAR(50) NOT NULL COMMENT '用户名' ,
admin_pwd VARCHAR(50) NOT NULL COMMENT '密码' ,
admin_role_id TINYINT UNSIGNED NOT NULL COMMENT '角色编号'
) ENGINE = INNODB charset = utf8 COMMENT '管理员表';
# 超级管理员测试数据
insert into ugo_admin values (null,'aa','aa',0);

#创建后台权限表
DROP TABLE IF EXISTS ugo_authority;
CREATE TABLE ugo_authority(
auth_id INT UNSIGNED auto_increment PRIMARY KEY COMMENT 'auth_id' ,
auth_name VARCHAR(50) NOT NULL COMMENT '权限名称' ,
auth_pid INT UNSIGNED NOT NULL COMMENT '权限父级id' ,
auth_c VARCHAR(50) NULL COMMENT '控制器名' ,
auth_a VARCHAR(50) NULL COMMENT '方法名' ,
auth_path VARCHAR(50) NULL COMMENT '全路径,格式:父级id-子级id' ,
is_show TINYINT NOT NULL DEFAULT 1 COMMENT '是否显示在导航栏上'
) ENGINE = INNODB charset = utf8 COMMENT '权限表';

#创建后台角色表
DROP TABLE IF EXISTS ugo_role;
CREATE TABLE IF NOT EXISTS ugo_role(
role_id TINYINT UNSIGNED auto_increment PRIMARY KEY COMMENT 'role_id' ,
role_name VARCHAR(50) NOT NULL COMMENT '角色名称' ,
role_auth_ids VARCHAR(255) NOT NULL COMMENT '角色具有权限id的集合,格式1,2,5' ,
role_auth_ac text NOT NULL COMMENT '控制器和方法的组合,格式:控制器-方法名'
) ENGINE = INNODB charset = utf8 COMMENT '角色表';

# *********************************************************** #
-- 插入测试数据
insert into ugo_authority values (1,'商品管理',0,'','',1,1);
insert into ugo_authority values (2,'会员管理',0,'','',2,1);
insert into ugo_authority values (3,'权限管理',0,'','',3,1);

insert into ugo_authority values (4,'商品列表',1,'Goods','show','1-4',1);
insert into ugo_authority values (5,'添加商品',1,'Goods','add','1-5',1);
insert into ugo_authority values (6,'修改商品',1,'Goods','edit','1-6',0);
insert into ugo_authority values (7,'删除商品',1,'Goods','del','1-7',0);

insert into ugo_authority values (8,'会员列表',2,'Role','show','2-12',1);
insert into ugo_authority values (9,'添加会员',2,'Role','add','2-13',1);
insert into ugo_authority values (10,'修改会员',2,'Role','edit','2-14',0);
insert into ugo_authority values (11,'删除会员',2,'Role','del','2-15',0);

insert into ugo_authority values (12,'权限列表',3,'Authority','show','3-8',1);
insert into ugo_authority values (13,'添加权限',3,'Authority','add','3-9',1);
insert into ugo_authority values (14,'修改权限',3,'Authority','edit','3-10',0);
insert into ugo_authority values (15,'删除权限',3,'Authority','del','3-11',0);

insert into ugo_role values (1,'经理','1,4,5','Goods-show,Goods-add');
insert into ugo_role values (2,'主管','1,4','Goods-show');

insert into ugo_admin values (null,'aa','aa',0)
# *********************************************************** #

菜单后台

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public function menu(){
$admin = session('admin');
$role_id = $admin['admin_role_id'];
if ($role_id==0) { //超级管理员
$auth_info1 = M('authority')->where('auth_pid = 0 and is_show = 1')->select();//父级
$auth_info2 = M('authority')->where('auth_pid > 0 and is_show = 1')->select();//子级
}else{
$role = M('role')->find($role_id); //通过管理员角色id找到角色信息
$role_auth_ids = $role['role_auth_ids'];//获取该角色的权限信息
$auth_info1 = M('authority')->where("auth_pid = 0 and is_show =1 and auth_id in ($role_auth_ids)")->select();
$auth_info2 = M('authority')->where("auth_pid > 0 and is_show =1 and auth_id in ($role_auth_ids)")->select();
}
$this->assign('menu_list',array(
'auth_info1' => $auth_info1,
'auth_info2' => $auth_info2
));
$this->display();
}

菜单前台

1
2
3
4
5
6
7
8
9
10
11
12
<volist name="menu_list.auth_info1" id="vo1">
<li class="collapse" key="{$i}_{$vo1.auth_c}" name="menu"> {$vo1.auth_name}
<ul style="display: none;">
<volist name="menu_list.auth_info2" id="vo2">
<li class="menu-item">
<a href="/index.php/Admin/{$vo2.auth_c}/{$vo2.auth_a}" target="main-frame"><if condition="$vo1.auth_id eq $vo2.auth_pid ">{$vo2.auth_name}</if>
</a>
</li>
</volist>
</ul>
</li>
</volist>

防翻墙与越权访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class BaseController extends Controller{
public function __construct(){
parent::__construct();
$this->chenkLogin();
}
// 防翻墙
public function chenkLogin(){
if (strtoupper(CONTROLLER_NAME)=='LOGIN') {
return;
}
$info = session('admin');
if (!$info) {
echo '<script type="text/javascript">';
echo "parent.location.href='/index.php/Admin/Public/login'";
echo '</script>';
exit;
}
//放置越权访问
if ($info['admin_role_id']==0) {
return;
}
//非管理员验证是否具有访问权限(防止越权方法)
$allow_controller_array = array('INDEX');//所有权限都可以访问Index控制器
$controller_name = strtoupper(CONTROLLER_NAME);//将当前控制器名转大写
if (!in_array($controller_name, $allow_controller_array)) {
$role = M('role')->find($info['admin_role_id']);
$allow_auth_ac = $role['role_auth_ac'];//当前角色允许的权限
$now_auth_ac = CONTROLLER_NAME . '-' . ACTION_NAME; //当前角色访问权限
if (FALSE === stripos($allow_auth_ac, $now_auth_ac)) {
$this->error('您没有此访问权限');
}
}
}
}

五张表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
RBAC建表
三张主表
管理员表(it_admin) 角色表(it_role) 权限表(it_privilege)
两张中间表
角色表与权限表的关系(多对多)it_role_privilege
一个角色,拥有多个权限
一个权限,所属多个角色
管理员表与角色表的关系(多对多)it_admin_role
一个角色拥有多个管理员
一个管理员也可以属于多个角色

#创建一个管理员表
create table it_admin(
id int unsigned primary key auto_increment,
admin_name varchar(32) not null comment '管理员名称',
password char(32) not null comment '管理员密码',
salt char(6) not null comment '密码的密钥'
)engine myisam charset utf8;

密码的加密方式是这样的,md5(md5(password).salt)
#在建管理员表时,要手工创建一个超级管理员
密码:'admin'
salt: df8trr
insert into it_admin(admin_name,password,salt) values('admin','a2040d1137c482b2b5379efb11909db5','df8trr');
#创建一个角色表
create table it_role(
id int unsigned primary key auto_increment,
role_name varchar(32) not null comment '角色名称'
)engine myisam charset utf8;
#创建一个权限表(节点,按钮) 权限就是按钮
create table it_privilege(
id int unsigned primary key auto_increment,
priv_name varchar(32) not null comment '权限名称',
parent_id int not null default 0 comment '权限的父权限',
module_name varchar(32) not null comment '权限对应模块的名称',
controller_name varchar(32) not null comment '权限对应控制器的名称',
action_name varchar(32) not null comment '权限对应方法的名称'
)engine myisam charset utf8;
#创建一个角色与权限的中间表
create table it_role_privilege(
role_id int not null comment '角色的id',
priv_id int not null comment '权限的id'
)engine myisam charset utf8;
#创建一个管理员与角色的中间表
create table it_admin_role(
admin_id int not null comment '管理员的id',
role_id int not null comment '角色的id'
)engine myisam charset utf8;