赞
踩
本篇主要讲权限管理(RBAC)
RBAC 是基于角色的访问控制(Role-Based Access Control )
翻译过来就是让不同角色拥有不同管理权限
后台需要登录
要有用户表
id | username | realname | password | salt | create_time | update_time | status |
---|---|---|---|---|---|---|---|
主键 | 用户名 | 真实姓名 | 密码 | 密码盐 | 创建时间 | 更新时间 | 用户状态 |
有了用户登录了以后肯定要见到需要管理的东西,我这里管理的东西是其他后台,为了不混淆概念给其他后台起个统一别名,改名为应用
于是有了应用表
id | keyword | name | create_time | update_time | status | app_url |
---|---|---|---|---|---|---|
主键 | 应用的关键词 | 应用名称 | 创建时间 | 更新时间 | 应用状态 | 应用后台的地址 |
现在当前登录的用户有了可以管理的东西了
有了应用以后就需要考虑角色问题了,一个应用中有诸多角色,比如运营,产品,测试,超级管理员等
角色表
id | app_id | name | auth | level | create_time | update_time | status |
---|---|---|---|---|---|---|---|
主键 | 角色对应用的id | 角色名称 | 角色所拥有的权限 | 角色的等级 | 创建时间 | 更新时间 | 角色状态 |
这里讲解一下,角色表是和应用表关联起来的,应用为参照物,应用=>角色
应该是一对多的关系。
角色=>应用
应该是一对一的关系。
现在有了用户表、应用表、角色表,要知道最终要实现的是对资源(路由)的管理控制,所以还需要另一个管理资源的表
资源表
id | app_id | fid | name | url | is_show | create_time | update_time |
---|---|---|---|---|---|---|---|
主键 | 资源所属哪个应用 | 资源的父级id(无限极分类使用) | 资源(路由)名称 | 是否显示该路由 | 创建时间 | 更新时间 | 资源状态(是否启用) |
现在一共创建了4张表分别是
1.用户表 (管理用户)
2.应用表 (管理应用)
3.角色表 (管理角色)
4.资源表(管理控制器方法资源)
现在需要想一个问题?
我想去给应用A下的角色运营A分配一个Banner管理权限该如何把这4张表联系起来?
即如何表述 用户 角色 和 资源(权限)之间的关系。
可以这样实现
用一张表记录上用户id、角色id、应用id
所以第五张表诞生了
关系表
id | app_id | role_id | user_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(" ", $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; }
后端整体实现思路:
每次更新权限时,数据库先更新,从数据库查询出更新后的数据存入缓存。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。