RBAC权限控制实现原理——权限表、用户表与关联表设计

RBAC权限控制实现原理——权限表、用户表与关联表设计,第1张

概述RBAC权限控制实现原理——权限表用户表与关联表设计 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

<?PHPnamespace 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;/**权限认证类**/

<?PHPuse think\facade\Db;use think\facade\Config;use think\facade\Session;use think\facade\Request;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];    }}

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

<?PHPnamespace 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权限控制实现原理——权限表、用户表与关联表设计全部内容,希望文章能够帮你解决RBAC权限控制实现原理——权限表、用户表与关联表设计所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/sjk/1150005.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存