上文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

PHP在現代編程中仍然是一個強大且廣泛使用的工具,尤其在web開發領域。 1)PHP易用且與數據庫集成無縫,是許多開發者的首選。 2)它支持動態內容生成和麵向對象編程,適合快速創建和維護網站。 3)PHP的性能可以通過緩存和優化數據庫查詢來提升,其廣泛的社區和豐富生態系統使其在當今技術棧中仍具重要地位。

在PHP中,弱引用是通過WeakReference類實現的,不會阻止垃圾回收器回收對象。弱引用適用於緩存系統和事件監聽器等場景,需注意其不能保證對象存活,且垃圾回收可能延遲。

\_\_invoke方法允許對象像函數一樣被調用。 1.定義\_\_invoke方法使對象可被調用。 2.使用$obj(...)語法時,PHP會執行\_\_invoke方法。 3.適用於日誌記錄和計算器等場景,提高代碼靈活性和可讀性。

Fibers在PHP8.1中引入,提升了並發處理能力。 1)Fibers是一種輕量級的並發模型,類似於協程。 2)它們允許開發者手動控制任務的執行流,適合處理I/O密集型任務。 3)使用Fibers可以編寫更高效、響應性更強的代碼。

PHP社區提供了豐富的資源和支持,幫助開發者成長。 1)資源包括官方文檔、教程、博客和開源項目如Laravel和Symfony。 2)支持可以通過StackOverflow、Reddit和Slack頻道獲得。 3)開發動態可以通過關注RFC了解。 4)融入社區可以通過積極參與、貢獻代碼和學習分享來實現。

PHP和Python各有優勢,選擇應基於項目需求。 1.PHP適合web開發,語法簡單,執行效率高。 2.Python適用於數據科學和機器學習,語法簡潔,庫豐富。

PHP不是在消亡,而是在不斷適應和進化。 1)PHP從1994年起經歷多次版本迭代,適應新技術趨勢。 2)目前廣泛應用於電子商務、內容管理系統等領域。 3)PHP8引入JIT編譯器等功能,提升性能和現代化。 4)使用OPcache和遵循PSR-12標準可優化性能和代碼質量。

PHP的未來將通過適應新技術趨勢和引入創新特性來實現:1)適應云計算、容器化和微服務架構,支持Docker和Kubernetes;2)引入JIT編譯器和枚舉類型,提升性能和數據處理效率;3)持續優化性能和推廣最佳實踐。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

MinGW - Minimalist GNU for Windows
這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

SublimeText3 Linux新版
SublimeText3 Linux最新版

DVWA
Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

Atom編輯器mac版下載
最受歡迎的的開源編輯器

Safe Exam Browser
Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。