是先设计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].[…

判断页面关闭的方法 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…

python考试有什么用_Python有什么用?2020年学习Python的10个理由

如果你想学习 Python&#xff0c;但是不知道为什么要学习&#xff0c;那么这里有 10 个理由&#xff0c;强调了在 2020 年学习 Python 的好处。不过&#xff0c;这些问题取决于谁在问&#xff0c;也就是说&#xff0c;对于初学者来说&#xff0c;学习Python是有意义的&#xff…

NDoc修改版,支持中文注释及中文界面。

这几天正在做一个项目的开发文档&#xff0c;以前试用NDoc做开发文档时不支持中文&#xff0c;真是不爽。这几天看了源代码&#xff0c;修改了其中的一段源代码及配置文件后&#xff0c;支持中文注释及中文界面&#xff08;目前只做了Msdn2003一种&#xff09;。以下为修改后版…

sql-bench mysql_MySQL性能测试(一)——RHEL 7.1, MySQL 5.6.25, sql-bench

由于前段时间要测试全闪存阵列上运行MySQL的性能&#xff0c;因此研究了段时间&#xff0c;试验了两个工具&#xff1a;一个是MySQL自带的sql-bench&#xff0c;一个是sysbench。本过程使用的环境是Redhat Enterprise Linux 7.1, MySQL 5.6.25&#xff0c;测试工具则是mysql自带…

java面试技术问题_11个JAVA面试中常见技术问题

原标题&#xff1a;11个JAVA面试中常见技术问题大家在平常面试java的过程中都会遇到哪些难题呢&#xff1f;还有一些即将去面试java的童鞋们&#xff0c;你们想知道技术面试中会涉及到哪些点吗&#xff1f;达妹为你整理Java面试中会被问到的几个技术难题。1、一个".java&q…

Java list接口

list中的元素可以重复&#xff0c;父接口是collection&#xff0c;实现类是&#xff1a;arraylist和vector。 arraylist&#xff1a; package com.jike.list;import java.util.ArrayList; import java.util.List;public class ListDemo01 {public static void main(String[] ar…

苏州游记

已经很久没有更新这里了&#xff0c;懒哦&#xff01;上周末一干人等去了苏州的三山岛&#xff0c;很是开心&#xff0c;春天来了&#xff0c;到处都是那么的生机盎然&#xff01;三山岛是太湖上若干岛屿之一&#xff0c;离苏州城很远&#xff0c;我们乘了50分钟的火车后&#…

markdown 转义字符

\\ 反斜杠   \ 反引号   \* 星号   \_ 下划线   \{\} 大括号   \[\] 中括号   \(\) 小括号   \# 井号   \ 加号   \- 减号   \. 英文句号   \! 感叹号 转载于:https://www.cnblogs.com/willingtolove/p/10456027.html

cadence 旋转快捷键_cadence原理图快捷键

原标题&#xff1a;cadence原理图快捷键Allegro Design Entry CIS 原理图1.shift鼠标滚轮 左右移动2.Ctrl鼠标滚轮 放大缩小3.Alt鼠标滚轮 上下移动4.按下鼠标滚轮可任意方向拖动图纸(可以一直保持按下状态或者按一下松开)5.CTRL鼠标左键 &#xff1a; 元件叠选6.CTRL鼠标左键拖…

Lab 11-1

Analyze the malware found in Lab11-01.exe. Questions and Short Answers What does the malware drop to disk? A: The malware extracts and drops the file msgina32.dll onto disk from a resource section named TGAD.How does the malware achieve persistence? A: T…

head first java原文_Head First Java

条件语句&和|可以用作条件语句&#xff0c;但是是长连接&#xff0c;左右两边的表达式必须都执行完&#xff01;这和&&和||不同&#xff0c;&&和||是短连接&#xff0c;只要左边的表达式已经能够计算出整个表达式的结果&#xff0c;右边的表达式就不会执行…

C#操作XML

已知有一个XML文件&#xff08;bookstore.xml&#xff09;如下&#xff1a; <?xml version"1.0"encoding"gb2312"?><bookstore><book genre"fantasy"ISBN"2-3631-4"><title>Oberons Legacy</title> &…