我是靠谱客的博主 优美超短裙,这篇文章主要介绍RBAC权限控制实现原理——权限表、用户表与关联表设计,现在分享给大家,希望可以做个参考。

RBAC是英文Role-based Access Control的首字母缩写,中文意思是基础角色的权限控制,它是一种思想,根据 RBAC 思想进行数据表设计,更好的完成不同角色的对应的权限控制。


如何使用RBAC思想进行数据表的设计


如果我们的项目允许一个后台管理用户可能有1个或者2个及2个以上的多个角色,按照下面进行设计:


11.png

权限菜单表,角色表,用户表是互相独立的。设计表的顺序是权限菜单表,角色表,用户表,用户-角色关联表。

1. 首先是权限菜单表设计如下:

注意:权限菜单可以是多级菜单,添加pid字段,方便无限极递归分类。

11.png

2. 角色表设计如下:

11.png

3. 用户表设计如下:

11.png

4. 最后是用户-角色关联表设计如下:

11.png

当超级管理员在后台需要添加新用户时,不仅需要insert数据进用户表,也需要在用户-角色表中添加用户和角色的关系。与之对应,删除用户时,也需要将用户-角色表中对应的用户-角色关系删除。

复制代码
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
public function add() { if(request()->isPost()){ $role_id = input('post.role_id'); $data = [ 'uname'=>input('post.uname'), 'pwd'=>password_hash(input('post.pwd'),PASSWORD_BCRYPT), 'login_ip'=>request()->ip(), 'status'=>input('post.status'), 'create_time'=>time(), ]; $uid = Db::name('users')->insertGetId($data); if($uid){ $data = [ 'uid'=>$uid, 'role_id'=>$role_id ]; $id = Db::name('users_role')->insertGetId($data); if($id) { echo 'true'; exit; }else{ echo 'false'; exit; } }else{ echo 'false'; exit; } }else{ //获取所有角色 $role = Db::name('auth_role')->field('id,title')->order('id','asc')->where('status',1)->select(); return view('add',['role'=>$role]); } }
登录后复制

这样以来我们根据用户登录以后session中储存的uid判断当前登录用户的身份信息,根据获取到的uid查询用户-角色关联表查询到用户的角色id, 然后到角色表获取到该用户可操作的权限菜单。

封装中间控制器Common.php

复制代码
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
<?php namespace appadmincontroller; use appBaseController; use thinkfacadeSession; use libAuth;/**权限认证类**/ class Common extends BaseController { public function initialize(){ $sess_auth = session('uid'); $uname = session('uname'); //判断用户是否登录 if(!$sess_auth){ jumpTo('/login/index'); exit; //检查到用户登录后, 还要检测该用户是否具有操作某个页面的权限, (是否具有操作某个方法的权限) }else{ $auth = new Auth(); if(!$auth->check(request()->controller().'/'.request()->action(),$sess_auth)){ historyTo('抱歉~你没有操作该栏目的权限,请联系管理员!'); exit; } } } }
登录后复制

libAuth;/**权限认证类**/

复制代码
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
<?php use thinkfacadeDb; use thinkfacadeConfig; use thinkfacadeSession; use thinkfacadeRequest; class Auth { protected $_config = [ 'auth_on' => true, // 认证开关 'auth_type' => 1, // 认证方式,1为实时认证;2为登录认证。 'auth_role' => 'auth_role', // 用户组数据表名 'users_role' => 'users_role', // 用户-用户组关系表 'auth_rule' => 'auth_rule', // 权限规则表 'auth_user' => 'users', // 用户信息表 ]; public function __construct() { if (Config::get('app.auth')) { $this->_config = array_merge($this->_config, Config::get('app.auth')); } } /** * 检查权限 * @param string|array $name 需要验证的规则列表,支持逗号分隔的权限规则或索引数组 * @param integer $uid 认证用户ID * @param string $relation 如果为 'or' 表示满足任一条规则即通过验证;如果为 'and' 则表示需满足所有规则才能通过验证 * @param string $mode 执行check的模式 * @param integer $type 规则类型 * @return boolean 通过验证返回true;失败返回false */ public function check($name, $uid, $relation = 'or', $mode = 'url', $type = 1) { if (!$this->_config['auth_on']) { return true; } $authList = $this->getAuthList($uid, $type); if (is_string($name)) { $name = strtolower($name); if (strpos($name, ',') !== false) { $name = explode(',', $name); } else { $name = [$name]; } } $list = []; if ($mode === 'url') { $REQUEST = unserialize(strtolower(serialize($_REQUEST))); } foreach ($authList as $auth) { $query = preg_replace('/^.+?/U', '', $auth); if ($mode === 'url' && $query != $auth) { parse_str($query, $param); // 解析规则中的param $intersect = array_intersect_assoc($REQUEST, $param); $auth = preg_replace('/?.*$/U', '', $auth); if (in_array($auth, $name) && $intersect == $param) { $list[] = $auth; } } elseif (in_array($auth, $name)) { $list[] = $auth; } } if ($relation === 'or' && !empty($list)) { return true; } $diff = array_diff($name, $list); if ($relation === 'and' && empty($diff)) { return true; } return false; } /** * 根据用户ID获取用户组,返回值为数组 * @param integer $uid 用户ID * @return array 用户所属用户组 ['uid'=>'用户ID', 'group_id'=>'用户组ID', 'title'=>'用户组名', 'rules'=>'用户组拥有的规则ID,多个用英文,隔开'] */ public function getGroups($uid) { static $groups = []; if (isset($groups[$uid])) { return $groups[$uid]; } $user_groups = Db::name($this->_config['users_role']) ->alias('ur') ->where('ur.uid', $uid) ->where('ar.status', 1) ->join($this->_config['auth_role'].' ar', "ur.role_id = ar.id") ->field('uid,role_id,title,rules') ->select(); $groups[$uid] = $user_groups ?: []; return $groups[$uid]; } /** * 获得权限列表 * @param integer $uid 用户ID * @param integer $type 规则类型 * @return array 权限列表 */ protected function getAuthList($uid, $type) { static $_authList = []; $t = implode(',', (array)$type); if (isset($_authList[$uid.$t])) { return $_authList[$uid.$t]; } if ($this->_config['auth_type'] == 2 && Session::has('_AUTH_LIST_'.$uid.$t)) { return Session::get('_AUTH_LIST_'.$uid.$t); } // 读取用户所属用户组 $groups = $this->getGroups($uid); $ids = []; // 保存用户所属用户组设置的所有权限规则ID foreach ($groups as $g) { $ids = array_merge($ids, explode(',', trim($g['rules'], ','))); } $ids = array_unique($ids); if (empty($ids)) { $_authList[$uid.$t] = []; return []; } $map = [ ['id', 'in', $ids], ['type', '=', $type], ['status', '=', 1] ]; // 读取用户组所有权限规则 $rules = Db::name($this->_config['auth_rule'])->where($map)->field('condition,name')->select(); // 循环规则,判断结果。 $authList = []; foreach ($rules as $rule) { if (!empty($rule['condition'])) { // 根据condition进行验证 $user = $this->getUserInfo($uid); // 获取用户信息,一维数组 $command = preg_replace('/{(w*?)}/', '$user['\1']', $rule['condition']); // dump($command); // debug @(eval('$condition=('.$command.');')); if ($condition) { $authList[] = strtolower($rule['name']); } } else { // 只要存在就记录 $authList[] = strtolower($rule['name']); } } $_authList[$uid.$t] = $authList; if ($this->_config['auth_type'] == 2) { Session::set('_AUTH_LIST_'.$uid.$t, $authList); } return array_unique($authList); } /** * 获得用户资料,根据自己的情况读取数据库 */ protected function getUserInfo($uid) { static $user_info = []; $user = Db::name($this->config['auth_user']); // 获取用户表主键 $_pk = is_string($user->getPk()) ? $user->getPk() : 'uid'; if (!isset($user_info[$uid])) { $user_info[$uid] = $user->where($_pk, $uid)->find(); } return $user_info[$uid]; } }
登录后复制

这样就能实现路由操作权限的实时检测,比如我们让首页控制器继承中间控制器:

复制代码
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
<?php namespace appadmincontroller; use thinkRequest; use thinkfacadeDb;//db类 use thinkfacadeSession; use libRule; class Index extends Common { public function index() { $uname = session('uname'); $uid = session('uid'); // 根据uid,获取该用户相应的权限,连表查询 $res = Db::name('users')->alias('u')->where('u.uid',$uid) ->leftJoin('users_role ur','ur.uid = u.uid') ->leftJoin('auth_role ar','ar.id = ur.role_id') ->field('u.uid,u.uname,ar.rules') ->select()->toArray(); // dd($res); $rules = implode(",",array_column($res,'rules')); // dd( $rules); //in查询 根据获取到的rules id 选权限列表 $res = Db::name('auth_rule')->field('id,name,title,pid')->order('id','asc')->where('is_menu',1) ->where('id','in',$rules)->select(); // dump($res); //这里使用扩展类Rule中封装的无限极分类方法 $rlist = Rule::Rulelayer($res); // dd($rlist); $data = [ 'uid'=>$uid, 'uname'=>$uname, 'rlist'=>$rlist, 'create_time'=>1617252175 ]; return view('index', $data); } }
登录后复制

最终实现的效果如图:

11.png


以上就是RBAC权限控制实现原理——权限表、用户表与关联表设计的详细内容,更多请关注靠谱客其它相关文章!

最后

以上就是优美超短裙最近收集整理的关于RBAC权限控制实现原理——权限表、用户表与关联表设计的全部内容,更多相关RBAC权限控制实现原理——权限表、用户表与关联表设计内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(291)

评论列表共有 0 条评论

立即
投稿
返回
顶部