温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

PHP与RBAC设计思路和数据表设计以及源码是怎样的

发布时间:2021-10-11 11:22:44 来源:亿速云 阅读:151 作者:柒染 栏目:大数据

这篇文章将为大家详细讲解有关PHP与RBAC设计思路和数据表设计以及源码是怎样的,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。

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

权限控制有哪些模型

  • ACL

  • RBAC 基于角色的访问控制

PHP与RBAC设计思路和数据表设计以及源码是怎样的

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

什么是RBAC模型

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

为什么要选择RBAC模型

原因如下:

  • 方便用户分组

  • 方便权限分配和回收

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

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

RBAC模型的关系图

PHP与RBAC设计思路和数据表设计以及源码是怎样的

图中有重要的RBAC模型5大属性,分别是:
1 用户属性(张三、李四、王五)
2 角色属性(销售经理、销售、前台)
3 用户与角色的关系(张三 是 销售经理 、李四 王五 是 销售)
4 权限(添加客户、编辑客户、删除客户,查看客户)
5 权限与角色的关系(销售 拥有 查看客户的 权 限、销售经理可以 查看/添加/删除/编辑客户的)

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

  • 用户管理
    用户列表
    添加用户
    编辑用户
    设置用户角色

  • 角色管理 角色列表
    添加角色
    编辑角色
    设置角色权限

  • 权限管理
    权限列表
    新增权限
    编辑权限

如图所示

PHP与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 ;
}

关于PHP与RBAC设计思路和数据表设计以及源码是怎样的就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI