php+layui实现大型后台权限管理(RBAC)

5 篇文章 0 订阅
5 篇文章 0 订阅
本文详细介绍了如何构建一个基于角色的访问控制(RBAC)系统,包括用户表、应用表、角色表和资源表的设计,以及如何通过关系表实现用户角色与资源权限的关联。在Yii2框架下,利用Layui前端展示,通过Redis缓存提升效率,文章还提供了资源无限极分类的代码示例和资源新增的操作方法。
摘要由CSDN通过智能技术生成

在这里插入图片描述
本篇主要讲权限管理(RBAC)

RBAC是什么?

RBAC 是基于角色的访问控制(Role-Based Access Control )
翻译过来就是让不同角色拥有不同管理权限

RBAC怎么实现?

后台需要登录
要有用户表

idusernamerealnamepasswordsaltcreate_timeupdate_timestatus
主键用户名真实姓名密码密码盐创建时间更新时间用户状态

有了用户登录了以后肯定要见到需要管理的东西,我这里管理的东西是其他后台,为了不混淆概念给其他后台起个统一别名,改名为应用

于是有了应用表

idkeywordnamecreate_timeupdate_timestatusapp_url
主键应用的关键词应用名称创建时间更新时间应用状态应用后台的地址

现在当前登录的用户有了可以管理的东西了
在这里插入图片描述

有了应用以后就需要考虑角色问题了,一个应用中有诸多角色,比如运营,产品,测试,超级管理员等

角色表

idapp_idnameauthlevelcreate_timeupdate_timestatus
主键角色对应用的id角色名称角色所拥有的权限角色的等级创建时间更新时间角色状态

这里讲解一下,角色表是和应用表关联起来的,应用为参照物,应用=>角色应该是一对多的关系。
角色=>应用应该是一对一的关系。
在这里插入图片描述

现在有了用户表、应用表、角色表,要知道最终要实现的是对资源(路由)的管理控制,所以还需要另一个管理资源的表

资源表

idapp_idfidnameurlis_showcreate_timeupdate_time
主键资源所属哪个应用资源的父级id(无限极分类使用)资源(路由)名称是否显示该路由创建时间更新时间资源状态(是否启用)

在这里插入图片描述
现在一共创建了4张表分别是
1.用户表 (管理用户)
2.应用表 (管理应用)
3.角色表 (管理角色)
4.资源表(管理控制器方法资源)

现在需要想一个问题?
我想去给应用A下的角色运营A分配一个Banner管理权限该如何把这4张表联系起来?
即如何表述 用户 角色 和 资源(权限)之间的关系。
可以这样实现

用一张表记录上用户id、角色id、应用id

所以第五张表诞生了

关系表

idapp_idrole_iduser_id
主键应用表的主键id角色表的主键id用户表的主键id

为什么没有资源表的主键id呢?因为资源表中已经有了与应用表作为关联的外键(join查询 或者 in 都可以),所以关联了应用id就相当于关联了资源表。

关系表最终实现的是一种关系记录,例如:张三拥有官网banner的banner的curd操作
在这里插入图片描述

部分代码:
前端Layui+后端Yii2+缓存Redis

1.资源表遍历无限极分类(为前端美化所提供的方法)

public static function getTree($data, $id, $fid = '', $spac = 0)
    {
        if (empty($data)) {
            return '';
        }
        //子类每次后面追加2个空格
        $spac = $spac + 2;
        static $str;
        foreach ($data as $k => $v) {
            if ($v['fid'] == $id) {
                if ($id == 0) {
                //这里可以改成根据自己需要的样式
                    $str .= "<option value='" . $v['id'] . "'";
                    if ($fid == $v['id']) {
                        $str .= ' selected';
                    }
                    $str .= ">" . $v['name'] . "</option>";
                } else {
                    $str .= "<option value='" . $v['id'] . "'";
                    if ($fid == $v['id']) {
                        $str .= ' selected';
                    }
                    $str .= ">" . str_repeat("&nbsp;", $spac) . "|--" . $v['name'] . "</option>";
                }
                self::getTree($data, $v['id'], $fid, $spac);
            }

        }

        return $str;
    }

2.资源新增
在这里插入图片描述

public function saveData($params)
    {
        $data = [];
        //这里如果是修改的话 可以改成  $model = self::findOne(主键ID);
        $model = new self();

        $data['app_id'] = intval($params['app_id']);
        $data['fid'] = intval($params['fid']);
        $data['name'] = trim($params['name']);
        $data['url'] = trim($params['url']);
        $data['is_show'] = intval($params['is_show']);
        $data['create_time'] = time();

        $model->setAttributes($data);

        try {
            if ($model->validate() && $model->save()) {
                //更新缓存
                $app_id = $model->app_id;
                $functionData = self::find()->where(['app_id' => $app_id])->all();
		        $functionArr = Functions::getArrTree($functionData, 0);
		        $appKeyword = App::find()->select('keyword')->where(['id' => $app_id])->scalar();
		        $cache = new BaseCache();
		        //设置好redis的 key
		        $cacheKey = CacheKey::BASE_BACKEND_RESOURCES_KEY.$appKeyword;
		        //redis set
		        $cache->set($cacheKey, json_encode($functionArr, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES));

                return ['status' => 1, 'msg' => '添加成功'];
            } else {
                $errors = array_values($model->getFirstErrors());
                throw new Exception($errors[0]);
            }
        } catch (Exception $e) {
            return ['status' => 0, 'msg' => $e->getMessage()];
        }
    }
    public static function getArrTree($data, $fid)
    {
        if (empty($data)) {
            return '';
        }
        $tree = [];
        foreach ($data as $k => $v) {
            if ($v['fid'] == $fid) {
                $rdata['id'] = $v['id'];
                $rdata['fid'] = $v['fid'];
                $rdata['name'] = $v['name'];
                $rdata['url'] = $v['url'];
                $rdata['is_show'] = $v['is_show'];
                $rdata['child'] = self::getArrTree($data, $rdata['id']);
                $tree[] = $rdata;
            }
        }
        return $tree;
    }
    //为了存进缓存的无限极分类
	public static function getArrTree($data, $fid)
	    {
	        if (empty($data)) {
	            return '';
	        }
	        $tree = [];
	        foreach ($data as $k => $v) {
	            if ($v['fid'] == $fid) {
	                $rdata['id'] = $v['id'];
	                $rdata['fid'] = $v['fid'];
	                $rdata['name'] = $v['name'];
	                $rdata['url'] = $v['url'];
	                $rdata['is_show'] = $v['is_show'];
	                $rdata['child'] = self::getArrTree($data, $rdata['id']);
	                $tree[] = $rdata;
	            }
	        }
	        return $tree;
	    }

在这里插入图片描述
后端整体实现思路:
每次更新权限时,数据库先更新,从数据库查询出更新后的数据存入缓存。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

PHP开光程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值