RBAC权限控制的实现原理

57次阅读
没有评论

共计 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 小编将为大家输出更多高质量的实用文章!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-28发表,共计6491字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)