上文http://www.BkJia.com/kf/201205/129972.html给大家讲解了使用循环输出九九乘法表,逻辑上还是相对简单一些,重在给大家提供一种看程序,解析代码的方法和思路,有什么意见或者建议可以跟帖批斗....
好了,不多说了,本文来给大家介绍一下“基于角色的访问控制 ”,
说到权限,大家就很头疼,怎么样能灵活把控好一个用户的权限,
有些同学会在用户表中加字段或者是在角色表中加相应的权限字段,
这样会有一个问题,做起权限来会感觉特别的蹩脚,而且很不灵活,每增加一种权限就要在数据库中增加一个字段,很不利于项目的迭代开发
那么我们就需要一种非常灵活的设计模式RBAC,即基于角色的访问控制;
我来给大家说下这种设计思想:
首先,我们的需求是判断某一个用户对当前操作的控制器或控制器的方法是否有权限访问,
如果多个用户同时拥有同样的权限,那我们就需要给这些用户指定同一个用户角色,然后只需要通过角色来对操作的访问进行权限控制,
那我们表结构需要这样来设计,这个很重要,如下:
第一张数据表(用户表):
字段名称 | 字段说明 |
id | 用户ID(主键自增) |
username | 用户名 |
password | 用户密码 |
第二张数据表(角色表):
字段名称 | 字段说明 |
id | 用户角色ID(主键自增) |
name | 用户角色名称 |
第三张数据表(节点表):
字段名称 | 字段说明 |
id | 操作节点ID(主键自增) |
name | 操作节点的名称 |
zh_name | 节点的中文说明 |
我们使用第三范式来设计关联表,这样做的好处是,避免数据冗余,并且对于一对多,多对一的关系都可以清晰的记录,条理清晰
第四张数据表(节点对应角色表):
字段名称 | 字段说明 |
role_id | 用户角色ID(外键,关联角色表中的主键ID) |
note_id | 操作节点ID(外键,关联节点表中的主键ID) |
第五张数据表(用户对应角色表):
字段名称 | 字段说明 |
role_id | 用户角色ID(外键,关联角色表中的主键ID) |
user_id | 用户ID(外键,关联用户表中的主键ID) |
通过这五张表就可以对权限进行访问控制,它的具体操作步骤如下:
用户输入用户名密码登录,
通过用户表判断,如果输入的用户名密码不合法,跳回重新登录
如果合法,在用户表中返回用户的ID号,
通过此用户ID号,到用户与角色的关联表中查询出用户的角色ID号,
拿到角色ID号,通过此ID号到角色与节点的关联表中查询出此角色拥有的节点访问权限,
将此权限节点全部存入SESSION中,当用户访问某一个模块的时候,
例如:http://www.lampbroher.net/index.php/stu/index
我们用session中的权限与$_GET['m']与$_GET['a']去对比,
如果$_GET['m']或者$_GET['a']在SESSION中不存在,说明该用户没有此权限,作出处理即可。
参考代码:
RBAC类文件:
/*+---------------------------------------------------------------------------------------+
| RBAC权限控制类
class Rbac{
private $node_tablename; //定义私有属性节点表名称
private $group_auth_tablename; //定义私有属性组权限表名称
private $group_tablename; //定义私有属性用户组表名称
private $group_user_tablename; //定义私有属性用户归属组表名称
private $user_tablename; //定义私有属性用户表名称
/*
构造方法
@param1 string 节点表名称
@param2 string 用户权限表名称
@param3 string 用户组表名称
@param4 string 用户归属组表名称
@param5 string 用户表名称
*/
public function __construct($node_tablename='node',$group_auth_tablename='group_auth',$group_tablename='group',$group_user_tablename='group_member',$user_tablename='member'){
$this->node_tablename = $node_tablename; //获取节点表名称
$this->group_auth_tablename = $group_auth_tablename; //获取用户权限表名称
$this->group_tablename = $group_tablename; //获取用户组表名称
$this->group_user_tablename = $group_user_tablename; //获取用户归属组表名称
$this->user_tablename = $user_tablename; //获取用户表名称
}
/*
设置节点方法
@param1 string 节点名称
@param2 string 节点父ID
@param2 string 节点中文说明
@return int 插入节点记录成功以后的ID
*/
public function set_node($name,$pid,$zh_name=''){
if(!empty($name) && !empty($pid)){
$node = D($this->node_tablename)->insert(array("name"=>$name,"pid"=>$pid,"zh_name"=>$zh_name));
}
return $node;
}
/*
设置权限方法
@param1 int 组ID
@param2 int 节点ID
@return int 插入权限记录成功以后的ID
*/
public function set_auth($gid,$nid){
if(!empty($gid) && !empty($nid)){
$auth = D($this->group_auth_tablename)->insert(array("gid"=>$gid,"nid"=>$nid));
}
return $auth;
}
/*
获取节点方法
@param1 int 节点ID
@return array 获取到节点表的相关信息
*/
public function get_node($id){
if(!empty($id)){
$data = D($this->node_tablename)->field("id,name,pid")->where(array('id'=>$id))->find();
return $data;
}else{
return false;
}
}
/*
获取组权限方法
@param1 int 用户组ID
@return array 获取到组权限表的相关信息
*/
public function get_auth($gid){
if(!empty($gid)){
$data = D($this->group_auth_tablename)->field("nid")->where(array('gid'=>$gid))->select();
return $data;
}else{
return false;
}
}
/*
获取用户组方法
@param1 int 用户ID
@return array 获取该用户所对应的用户组id
*/
public function get_group($uid){
if(!empty($uid)){
$data = D($this->group_user_tablename)->field("gid")->where(array('uid'=>$uid))->select();
return $data;
}else{
return false;
}
}
/*
获取节点的子节点方法
@param1 int 节点ID
@return array 获取该节点所对应的全部子节点
*/
public function get_cnode($nid){
if(!empty($nid)){
$cnode = D($this->node_tablename)->field("name")->where(array('pid'=>$nid))->select();
return $cnode;
}else{
return false;
}
}
/*
获取权限方法
@param1 int 用户ID
@return array 得到权限列表
*/
public function get_access($uid){
if(!empty($uid)){
//调用获取组信息方法
$group = $this->get_group($uid);
//遍历组信息
foreach($group as $v){
//将组ID传入获取权限的方法
$auth = $this->get_auth($v['gid']); //获取该组的权限
}
//遍历该组的权限数组
foreach($auth as $val){
//将节点的ID传入获取节点信息方法
$node[] = $this->get_node($val['nid']); //获取节点的相关信息
}
//遍历节点数组,并拼装
foreach($node as $nval){
if($nval['pid']==0){
$fnode[] = $nval; //将控制器压入fnode数组
//$cnode = $this->get_cnode($nval['id']);
}else{
$cnode[] = $nval; //将控制器的方法压入cnode数组
}
}
//将控制器数组和控制器数组拼装成一个数组
foreach($fnode as $fval){
foreach($cnode as $cval){
if($cval['pid'] == $fval['id']){
$access[$fval['name']][] = $cval['name'];
}
}
}
//返回权限列表数组
return $access;
}else{
return false;
}
}
/*
检测权限方法
@param1 int 用户ID
@return boolean 权限禁止与否
*/
public function check($uid){
if(!empty($uid)){
//将权限存入到$_SESSION['Access_List']中
$_SESSION['Access_List'] = $this->get_access($uid);
if(!empty($_GET['m'])){
//判断此控制器是否被允许
if(array_key_exists($_GET['m'],$_SESSION['Access_List'])){
//判断此控制器的方法是否被允许
if(in_array($_GET['a'],$_SESSION['Access_List'][$_GET['m']])){
//允许的话返回真
return true;
}else{
//否则返回假
return false;
}
}else{
return false;
}
}else{
return false;
}
}else{
//$_SESSION['user_'.$uid]['Access_List'] = 0;
return false;
}
}
public function show_node(){
$path = APP_PATH.'/controls/';
$handle = opendir($path);
while(false!==($data = readdir($handle))){
if(is_file($path.$data) && $data!='common.class.php' && $data!='pub.class.php'){
$controller = str_replace(".class.php",'',$data);
$res = fopen($path.$data,'r');
$str = fread($res,filesize($path.$data));
$pattern = '/function(.*)\(\)/iU';
preg_match_all($pattern, $str, $matches);
foreach($matches[1] as $v){
$v = trim($v);
$arr[$controller][] = $v;
}
}
}
closedir($handle);
return $arr;
}
}
初始化类:
/*+---------------------------------------------------------------------------------------+
| 初始化控制器
class Common extends Action {
/*
初始化方法
*/
public function init(){
//如果SESSION为空,则跳转
if(empty($_SESSION['user_login'])){
$this->redirect("pub/index");
}
$a = new rbac();
if(!$a->check($_SESSION['user_info']['id'])){
echo "<script>alert('您没有此权限!')</script>";
exit("<script>document.write('<span style=\'font-size:40px;font-weight:bold\'>Access Forbidden');alert('您没有此权限!');</script>");
$this->redirect("pub/index");
}
}
}
这里给大家写了一个简单的RBAC类,仅供大家学习参考此思想,如有问题可以跟帖回复....
作者 zdrjlamp

tomodifyDataNaphPsession,startTheSessionWithSession_start(),然后使用$ _sessionToset,修改,orremovevariables.1)startThesession.2)setthesession.2)使用$ _session.3)setormodifysessessvariables.3)emovervariableswithunset()

在PHP会话中可以存储数组。1.启动会话,使用session_start()。2.创建数组并存储在$_SESSION中。3.通过$_SESSION检索数组。4.优化会话数据以提升性能。

PHP会话垃圾回收通过概率机制触发,清理过期会话数据。1)配置文件中设置触发概率和会话生命周期;2)可使用cron任务优化高负载应用;3)需平衡垃圾回收频率与性能,避免数据丢失。

PHP中追踪用户会话活动通过会话管理实现。1)使用session_start()启动会话。2)通过$_SESSION数组存储和访问数据。3)调用session_destroy()结束会话。会话追踪用于用户行为分析、安全监控和性能优化。

利用数据库存储PHP会话数据可以提高性能和可扩展性。1)配置MySQL存储会话数据:在php.ini或PHP代码中设置会话处理器。2)实现自定义会话处理器:定义open、close、read、write等函数与数据库交互。3)优化和最佳实践:使用索引、缓存、数据压缩和分布式存储来提升性能。

phpsessionstrackuserdataacrossmultiplepagerequestsusingauniqueIdStoredInacookie.here'showtomanageThemeffectionaly:1)startAsessionWithSessionwwithSession_start()和stordoredAtain $ _session.2)

在PHP中,遍历会话数据可以通过以下步骤实现:1.使用session_start()启动会话。2.通过foreach循环遍历$_SESSION数组中的所有键值对。3.处理复杂数据结构时,使用is_array()或is_object()函数,并用print_r()输出详细信息。4.优化遍历时,可采用分页处理,避免一次性处理大量数据。这将帮助你在实际项目中更有效地管理和使用PHP会话数据。

会话通过服务器端的状态管理机制实现用户认证。1)会话创建并生成唯一ID,2)ID通过cookies传递,3)服务器存储并通过ID访问会话数据,4)实现用户认证和状态管理,提升应用安全性和用户体验。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

安全考试浏览器
Safe Exam Browser是一个安全的浏览器环境,用于安全地进行在线考试。该软件将任何计算机变成一个安全的工作站。它控制对任何实用工具的访问,并防止学生使用未经授权的资源。

记事本++7.3.1
好用且免费的代码编辑器

适用于 Eclipse 的 SAP NetWeaver 服务器适配器
将Eclipse与SAP NetWeaver应用服务器集成。

SublimeText3汉化版
中文版,非常好用

EditPlus 中文破解版
体积小,语法高亮,不支持代码提示功能