是先设计mysql表再进行php代码_PHP与RBAC设计思路,数据表设计与源码讲解

权限系统模块对于互联网产品是一个非常重要的功能,可以控制不同的角色合理的访问不同的资源从而达到安全访问的作用

权限控制有哪些模型ACL

RBAC 基于角色的访问控制

从上图我们可以看出,ACL是用户和权限直接关系的,而RBAC则是通过角色间接关联用户和权限的。所以我们注意到角色是RBAC系统的一个重要属性。

什么是RBAC模型

RBAC(Role-Based Access Control,基于角色的访问控制),就是用户通过角色与权限进行关联。简单地说,一个用户拥有若干角色,每一个角色拥有若干权限。这样,就构造成“用户-角色-权限”的授权模型。在这种模型中,用户与角色之间,角色与权限之间,一般者是多对多的关系。

为什么要选择RBAC模型

原因如下:方便用户分组

方便权限分配和回收

扩展方便,可以满足大部分业务需求

这些也就是我们在说权限管理前,应该先知道权限管理要有功能。

RBAC模型的关系图

图中有重要的RBAC模型5大属性,分别是:

1 用户属性(张三、李四、王五)

2 角色属性(销售经理、销售、前台)

3 用户与角色的关系(张三 是 销售经理 、李四 王五 是 销售)

4 权限(添加客户、编辑客户、删除客户,查看客户)

5 权限与角色的关系(销售 拥有 查看客户的 权 限、销售经理可以 查看/添加/删除/编辑客户的)

一个RBAC权限模块,必然要实现三个功能用户管理

用户列表

添加用户

编辑用户

设置用户角色

角色管理 角色列表

添加角色

编辑角色

设置角色权限

权限管理

权限列表

新增权限

编辑权限

如图所示

数据表设计

用户表

CREATE TABLE `user` (

`id` int(11) unsigned NOT NULL AUTO_INCREMENT,

`name` varchar(20) NOT NULL DEFAULT '' COMMENT '姓名',

`email` varchar(30) NOT NULL DEFAULT '' COMMENT '邮箱',

`is_admin` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否是超级管理员 1表示是 0 表示不是',

`status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态 1:有效 0:无效',

`updated_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '最后一次更新时间',

`created_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '插入时间',

PRIMARY KEY (`id`),

KEY `idx_email` (`email`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户表';

角色表

CREATE TABLE `role` (

`id` int(11) unsigned NOT NULL AUTO_INCREMENT,

`name` varchar(50) NOT NULL DEFAULT '' COMMENT '角色名称',

`status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态 1:有效 0:无效',

`updated_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '最后一次更新时间',

`created_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '插入时间',

PRIMARY KEY (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色表';

用户角色表

CREATE TABLE `user_role` (

`id` int(11) unsigned NOT NULL AUTO_INCREMENT,

`uid` int(11) NOT NULL DEFAULT '0' COMMENT '用户id',

`role_id` int(11) NOT NULL DEFAULT '0' COMMENT '角色ID',

`created_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '插入时间',

PRIMARY KEY (`id`),

KEY `idx_uid` (`uid`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户角色表';

权限详情表

CREATE TABLE `access` (

`id` int(11) unsigned NOT NULL AUTO_INCREMENT,

`title` varchar(50) NOT NULL DEFAULT '' COMMENT '权限名称',

`urls` varchar(1000) NOT NULL DEFAULT '' COMMENT 'json 数组',

`status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态 1:有效 0:无效',

`updated_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '最后一次更新时间',

`created_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '插入时间',

PRIMARY KEY (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='权限详情表';

角色权限表

CREATE TABLE `role_access` (

`id` int(11) unsigned NOT NULL AUTO_INCREMENT,

`role_id` int(11) NOT NULL DEFAULT '0' COMMENT '角色id',

`access_id` int(11) NOT NULL DEFAULT '0' COMMENT '权限id',

`created_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '插入时间',

PRIMARY KEY (`id`),

KEY `idx_role_id` (`role_id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色权限表';

用户操作记录表

CREATE TABLE `app_access_log` (

`id` int(11) NOT NULL AUTO_INCREMENT,

`uid` bigint(20) NOT NULL DEFAULT '0' COMMENT '品牌UID',

`target_url` varchar(255) NOT NULL DEFAULT '' COMMENT '访问的url',

`query_params` longtext NOT NULL COMMENT 'get和post参数',

`ua` varchar(255) NOT NULL DEFAULT '' COMMENT '访问ua',

`ip` varchar(32) NOT NULL DEFAULT '' COMMENT '访问ip',

`note` varchar(1000) NOT NULL DEFAULT '' COMMENT 'json格式备注字段',

`created_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,

PRIMARY KEY (`id`),

KEY `idx_uid` (`uid`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户操作记录表';

代码实现

本系统所有页面都是需要登录之后才能访问的, 在框架中加入统一验证方法

public function beforeAction($action) {

$login_status = $this->checkLoginStatus();

if ( !$login_status && !in_array( $action->uniqueId,$this->allowAllAction ) ) {

if(Yii::$app->request->isAjax){

$this->renderJSON([],"未登录,请返回用户中心",-302);

}else{

$this->redirect( UrlService::buildUrl("/user/login") );//返回到登录页面

}

return false;

}

//保存所有的访问到数据库当中

$get_params = $this->get( null );

$post_params = $this->post( null );

$model_log = new AppAccessLog();

$model_log->uid = $this->current_user?$this->current_user['id']:0;

$model_log->target_url = isset( $_SERVER['REQUEST_URI'] )?$_SERVER['REQUEST_URI']:'';

$model_log->query_params = json_encode( array_merge( $post_params,$get_params ) );

$model_log->ua = isset( $_SERVER['HTTP_USER_AGENT'] )?$_SERVER['HTTP_USER_AGENT']:'';

$model_log->ip = isset( $_SERVER['REMOTE_ADDR'] )?$_SERVER['REMOTE_ADDR']:'';

$model_log->created_time = date("Y-m-d H:i:s");

$model_log->save( 0 );

/**

* 判断权限的逻辑是

* 取出当前登录用户的所属角色,

* 在通过角色 取出 所属 权限关系

* 在权限表中取出所有的权限链接

* 判断当前访问的链接 是否在 所拥有的权限列表中

*/

//判断当前访问的链接 是否在 所拥有的权限列表中

if( !$this->checkPrivilege( $action->getUniqueId() ) ){

$this->redirect( UrlService::buildUrl( "/error/forbidden" ) );

return false;

}

return true;

}

检查是否有访问指定链接的权限

public function checkPrivilege( $url ){

//如果是超级管理员 也不需要权限判断

if( $this->current_user && $this->current_user['is_admin'] ){

return true;

}

//有一些页面是不需要进行权限判断的

if( in_array( $url,$this->ignore_url ) ){

return true;

}

return in_array( $url, $this->getRolePrivilege( ) );

}

获取某用户的所有权限,取出指定用户的所属角色, 在通过角色取出所属权限关系,在权限表中取出所有的权限链接

public function getRolePrivilege($uid = 0){

if( !$uid && $this->current_user ){

$uid = $this->current_user->id;

}

if( !$this->privilege_urls ){

$role_ids = UserRole::find()->where([ 'uid' => $uid ])->select('role_id')->asArray()->column();

if( $role_ids ){

//在通过角色 取出 所属 权限关系

$access_ids = RoleAccess::find()->where([ 'role_id' => $role_ids ])->select('access_id')->asArray()->column();

//在权限表中取出所有的权限链接

$list = Access::find()->where([ 'id' => $access_ids ])->all();

if( $list ){

foreach( $list as $_item ){

$tmp_urls = @json_decode( $_item['urls'],true );

$this->privilege_urls = array_merge( $this->privilege_urls,$tmp_urls );

}

}

}

}

return $this->privilege_urls ;

}

链接:http://www.startphp.cn/front/php/112730.html

作者:leifeng以上内容希望帮助到大家,很多PHPer在进阶的时候总会遇到一些问题和瓶颈,业务代码写多了没有方向感,不知道该从那里入手去提升,对此我整理了一些资料,包括但不限于:分布式架构、高可扩展、高性能、高并发、服务器性能调优、TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql优化、shell脚本、Docker、微服务、Nginx等多个知识点高级进阶干货需要的可以免费分享给大家

最后,祝所有大家在面试中过关斩将,拿到心仪offer。如果想与一群3-8年资深开发者一起交流学习的话,需要请戳这里​shimo.im9a4c2ba04ad85d1fc847cf953a7b5820.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/412176.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

自动化测试模型

自动化测试模型可以看作自动化测试框架与工具设计的思想。自动化测试不仅仅是单纯写脚本运行就可以了,还需要考虑到如何使脚本运行效率提高,代码复用、参数化等问题。自动化测试模型分为四大类:线性模型、模块化驱动测试、数据驱动、关键字驱…

SQL实现split函数,自定义分割字符,自定义取出第几个分割字符前的字符串

自定义取出第几个分割字符前的字符串,默认位置(0)格式:dbo.split(字段名,分隔字符,取出的第几个字符串)如果没有分隔的字符,则返回整个字符串。如果取出的位置字符串的位置超出Index则返回空。CREATE FUNCTION [dbo].[…

mysql 开发 生产_在没有表锁定的情况下在巨大的MySQL生产表...

[2017]更新:MySQL 5.6支持在线索引更新In MySQL 5.6 and higher, the table remains available for read and write operations while the index is being created or dropped. The CREATE INDEX or DROP INDEX statement only finishes after all transactions tha…

ListView性能优化

ListView在ScrollView中无法正确计算它的大小, 故不能显示正常的条目。 解决办法有: 1.重写ListView, 覆盖onMeasure()方法。 1 public class WrapperListView extends ListView {2 public WrapperListView(Context context) {3 super(context);4 }…

判断页面关闭的方法 UNLOAD/onbeforeunload

最近一个朋友做在线统计,问我怎么判断用户登陆和离开。获得用户登陆不用说了,大家都知道,判断离开的话就有一点问题了,如果说用户都是按照设计者的规定的范围触发退出事件离开的话那就没什么难度了,但是用户的离开方式…

mysql 第几周 时间戳_php时间戳函数实现计算第几周,以及当天所在周的具体日期范围...

<html><script language"javascript">function showdate(){c new Date(2008,1,29);//输入开学的日期.注意,月份是从0-11;comperc.getTime();//以2008年2月29日作为上半学期结束。然后记录新的开学日期var now new Date();//获取当前时间var d_nownow.ge…

java学习笔记④MySql数据库--03/04 DQL查询

03 使用DQL查询数据&#xff08;一&#xff09; 04 使用DQL查询数据&#xff08;二&#xff09; DQL 数据查询语言 select select * 方式效率低 AS 取别名 (给字段取别名,给表取别名,给计算结果取别名) as取别名时,可省略as distinct 去重 所有字段一起不重复算一条记录 selec…

2005国产空间信息系统软件测评结果揭晓

记者&#xff1a;云洲 来源&#xff1a;www.3sNews.net 责编&#xff1a;小柯 [3sNews讯]2005年12月27&#xff0c;为期两天的“地球观测与导航技术领域科技发展研讨会”于中国科技会堂胜利召开&#xff0c;备受业界关注的2005国产空间信息系统软件测评结果在会上揭晓&am…

mysql变量string_mysql sql语句有变量 time_t变量转换为string

1.char*变量 如果有两个指针变量不可以 需要一个转换为stringstring strCall ;strCall.assign(pCallInfo->m_szCallerNo,strlen(pCallInfo->m_szCallerNo));//char* 转换为stringstring sql "insert into tcallrecord values("strCall","pCallInfo-…

axios+vue实现动态渲染员工数据+数据是对象

<style>table{width: 600px;margin: 0 auto;text-align: center;border-collapse: collapse; /*合并边框哦*/}tr th,tr td{border: 1px solid pink;}</style><script src"../vue.js"></script><script src"../axios.js">&l…

[Translation]《击鼓》

"Live or die,meet or part,weve made oath,you and I;,7UZGive me your hand,Ill hold,and live together,till old.l"From: 《击鼓》I?©MYUP2U社区 -- 整理童年的记忆&#xff0c;释放知识的潜力&#xff0c;共享青春的激情&#xff0c;尽在MYUP2U&#xff0…

[vue] vue自定义事件中父组件怎么接收子组件的多个参数?

[vue] vue自定义事件中父组件怎么接收子组件的多个参数&#xff1f; 子组件传递多个参数&#xff0c;父组件用展开运算符获取个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关…

FLASH全屏,左右侧,闪烁广告及对错觉的代码补充.

<!--焦点图开始--> <script type"text/javascript"><!--var focus_width250; ------ flash的宽度var focus_height160; ------ flash的高度同样可以加上背景颜色 var focus_bgcolor160; ------ flash的背景颜色…

vscode调试angular2

调试步骤&#xff1a; 1.安装nodejs 2.安装vscode 3.vscode安装debugger for chrome插件 4.选择调试->打开调试配置&#xff0c;选择chrome配置&#xff0c;打开lauch.json,修改如下&#xff1a; {"version": "0.2.0","configurations": [{&q…

python实现组合问题_python3 最基本且简单的实现组合设计模式

&#xfeff;组合模式是把一个类别归为一个整体&#xff0c;并且组织多个整体之间的关系&#xff0c;使用通过树形结构来描述所有整体。一般的编写方式为一个类别对象下添加多个该对象的元素&#xff0c;该对象又为其它对象下的元素。简单来说就是一个学校有一个总部&#xff0…

[vue] 说下$attrs和$listeners的使用场景

[vue] 说下attrs和attrs和attrs和listeners的使用场景 <template><el-button v-on"$listeners" v-bind"$attrs" :loading"loading" click"myClick"><slot></slot></el-button> </template><s…