共计 6491 个字符,预计需要花费 17 分钟才能阅读完成。
本篇内容介绍了“RBAC 权限控制的实现原理”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让丸趣 TV 小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
RBAC 是英文 Role-based Access Control 的首字母缩写,中文意思是基础角色的权限控制,它是一种思想,根据 RBAC 思想进行数据表设计, 更好的完成不同角色的对应的权限控制。
如何使用 RBAC 思想进行数据表的设计
如果我们的项目允许一个后台管理用户可能有 1 个或者 2 个及 2 个以上的多个角色, 按照下面进行设计:
权限菜单表,角色表,用户表是互相独立的。设计表的顺序是权限菜单表,角色表,用户表,用户 - 角色关联表。
1. 首先是权限菜单表设计如下:
注意:权限菜单可以是多级菜单,添加 pid 字段,方便无限极递归分类。
2. 角色表设计如下:
3. 用户表设计如下:
4. 最后是用户 - 角色关联表设计如下:
当超级管理员在后台需要添加新用户时,不仅需要 insert 数据进用户表,也需要在用户 - 角色表中添加用户和角色的关系。与之对应,删除用户时,也需要将用户 - 角色表中对应的用户 - 角色关系删除。
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
?php
namespace app\admin\controller;
use app\BaseController;
use think\facade\Session;
use lib\Auth;/** 权限认证类 **/
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;
}
}
}
}
lib\Auth;/** 权限认证类 **/
?php
use think\facade\Db;
use think\facade\Config;
use think\facade\Session;
use think\facade\Request;
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];
}
}
这样就能实现路由操作权限的实时检测,比如我们让首页控制器继承中间控制器:
?php
namespace app\admin\controller;
use think\Request;
use think\facade\Db;//db 类
use think\facade\Session;
use lib\Rule;
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);
}
}
最终实现的效果如图:
“RBAC 权限控制的实现原理”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注丸趣 TV 网站,丸趣 TV 小编将为大家输出更多高质量的实用文章!