【捷哥浅谈PHP】第七弹 ---- 基于角色的访问控制RBAC

来源:互联网 发布:知乎 双肩包 独立品牌 编辑:程序博客网 时间:2024/06/15 21:27
上文给大家讲解了使用循环输出九九乘法表,逻辑上还是相对简单一些,重在给大家提供一种看程序,解析代码的方法和思路,有什么意见或者建议可以跟帖批斗....

好了,不多说了,本文来给大家介绍一下“基于角色的访问控制 ”,

说到权限,大家就很头疼,怎么样能灵活把控好一个用户的权限,

有些同学会在用户表中加字段或者是在角色表中加相应的权限字段,

这样会有一个问题,做起权限来会感觉特别的蹩脚,而且很不灵活,每增加一种权限就要在数据库中增加一个字段,很不利于项目的迭代开发

那么我们就需要一种非常灵活的设计模式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类文件:
  1. <?php
  2. /* ---------------------------------------------------------------------------------------
  3. | RBAC权限控制类
  4. -----------------------------------------------------------------------------------------
  5. | 版权所有 lamp兄弟连
  6. -----------------------------------------------------------------------------------------
  7. | 作者: 李捷 (lijie@li-jie.me)
  8. | 最后修改时间: 2012-05-06 18:30
  9. -----------------------------------------------------------------------------------------
  10. */
  11. class Rbac{
  12. private $node_tablename; //定义私有属性节点表名称
  13. private $group_auth_tablename; //定义私有属性组权限表名称
  14. private $group_tablename; //定义私有属性用户组表名称
  15. private $group_user_tablename; //定义私有属性用户归属组表名称
  16. private $user_tablename; //定义私有属性用户表名称
  17. /*
  18. 构造方法
  19. @param1 string 节点表名称
  20. @param2 string 用户权限表名称
  21. @param3 string 用户组表名称
  22. @param4 string 用户归属组表名称
  23. @param5 string 用户表名称
  24. */
  25. public function __construct($node_tablename='node',$group_auth_tablename='group_auth',$group_tablename='group',$group_user_tablename='group_member',$user_tablename='member'){
  26. $this->node_tablename = $node_tablename; //获取节点表名称
  27. $this->group_auth_tablename = $group_auth_tablename; //获取用户权限表名称
  28. $this->group_tablename = $group_tablename; //获取用户组表名称
  29. $this->group_user_tablename = $group_user_tablename; //获取用户归属组表名称
  30. $this->user_tablename = $user_tablename; //获取用户表名称
  31. }
  32. /*
  33. 设置节点方法
  34. @param1 string 节点名称
  35. @param2 string 节点父ID
  36. @param2 string 节点中文说明
  37. @return int 插入节点记录成功以后的ID
  38. */
  39. public function set_node($name,$pid,$zh_name=''){
  40. if(!empty($name) && !empty($pid)){
  41. $node = D($this->node_tablename)->insert(array("name"=>$name,"pid"=>$pid,"zh_name"=>$zh_name));
  42. }
  43. return $node;
  44. }
  45. /*
  46. 设置权限方法
  47. @param1 int 组ID
  48. @param2 int 节点ID
  49. @return int 插入权限记录成功以后的ID
  50. */
  51. public function set_auth($gid,$nid){
  52. if(!empty($gid) && !empty($nid)){
  53. $auth = D($this->group_auth_tablename)->insert(array("gid"=>$gid,"nid"=>$nid));
  54. }
  55. return $auth;
  56. }
  57. /*
  58. 获取节点方法
  59. @param1 int 节点ID
  60. @return array 获取到节点表的相关信息
  61. */
  62. public function get_node($id){
  63. if(!empty($id)){
  64. $data = D($this->node_tablename)->field("id,name,pid")->where(array('id'=>$id))->find();
  65. return $data;
  66. }else{
  67. return false;
  68. }
  69. }
  70. /*
  71. 获取组权限方法
  72. @param1 int 用户组ID
  73. @return array 获取到组权限表的相关信息
  74. */
  75. public function get_auth($gid){
  76. if(!empty($gid)){
  77. $data = D($this->group_auth_tablename)->field("nid")->where(array('gid'=>$gid))->select();
  78. return $data;
  79. }else{
  80. return false;
  81. }
  82. }
  83. /*
  84. 获取用户组方法
  85. @param1 int 用户ID
  86. @return array 获取该用户所对应的用户组id
  87. */
  88. public function get_group($uid){
  89. if(!empty($uid)){
  90. $data = D($this->group_user_tablename)->field("gid")->where(array('uid'=>$uid))->select();
  91. return $data;
  92. }else{
  93. return false;
  94. }
  95. }
  96. /*
  97. 获取节点的子节点方法
  98. @param1 int 节点ID
  99. @return array 获取该节点所对应的全部子节点
  100. */
  101. public function get_cnode($nid){
  102. if(!empty($nid)){
  103. $cnode = D($this->node_tablename)->field("name")->where(array('pid'=>$nid))->select();
  104. return $cnode;
  105. }else{
  106. return false;
  107. }
  108. }
  109. /*
  110. 获取权限方法
  111. @param1 int 用户ID
  112. @return array 得到权限列表
  113. */
  114. public function get_access($uid){
  115. if(!empty($uid)){
  116. //调用获取组信息方法
  117. $group = $this->get_group($uid);
  118. //遍历组信息
  119. foreach($group as $v){
  120. //将组ID传入获取权限的方法
  121. $auth = $this->get_auth($v['gid']); //获取该组的权限
  122. }
  123. //遍历该组的权限数组
  124. foreach($auth as $val){
  125. //将节点的ID传入获取节点信息方法
  126. $node[] = $this->get_node($val['nid']); //获取节点的相关信息
  127. }
  128. //遍历节点数组,并拼装
  129. foreach($node as $nval){
  130. if($nval['pid']==0){
  131. $fnode[] = $nval; //将控制器压入fnode数组
  132. //$cnode = $this->get_cnode($nval['id']);
  133. }else{
  134. $cnode[] = $nval; //将控制器的方法压入cnode数组
  135. }
  136. }
  137. //将控制器数组和控制器数组拼装成一个数组
  138. foreach($fnode as $fval){
  139. foreach($cnode as $cval){
  140. if($cval['pid'] == $fval['id']){
  141. $access[$fval['name']][] = $cval['name'];
  142. }
  143. }
  144. }
  145. //返回权限列表数组
  146. return $access;
  147. }else{
  148. return false;
  149. }
  150. }
  151. /*
  152. 检测权限方法
  153. @param1 int 用户ID
  154. @return boolean 权限禁止与否
  155. */
  156. public function check($uid){
  157. if(!empty($uid)){
  158. //将权限存入到$_SESSION['Access_List']中
  159. $_SESSION['Access_List'] = $this->get_access($uid);
  160. if(!empty($_GET['m'])){
  161. //判断此控制器是否被允许
  162. if(array_key_exists($_GET['m'],$_SESSION['Access_List'])){
  163. //判断此控制器的方法是否被允许
  164. if(in_array($_GET['a'],$_SESSION['Access_List'][$_GET['m']])){
  165. //允许的话返回真
  166. return true;
  167. }else{
  168. //否则返回假
  169. return false;
  170. }
  171. }else{
  172. return false;
  173. }
  174. }else{
  175. return false;
  176. }
  177. }else{
  178. //$_SESSION['user_'.$uid]['Access_List'] = 0;
  179. return false;
  180. }
  181. }
  182. public function show_node(){
  183. $path = APP_PATH.'/controls/';
  184. $handle = opendir($path);
  185. while(false!==($data = readdir($handle))){
  186. if(is_file($path.$data) && $data!='common.class.php' && $data!='pub.class.php'){
  187. $controller = str_replace(".class.php",'',$data);
  188. $res = fopen($path.$data,'r');
  189. $str = fread($res,filesize($path.$data));
  190. $pattern = '/function(.*)\(\)/iU';
  191. preg_match_all($pattern, $str, $matches);
  192. foreach($matches[1] as $v){
  193. $v = trim($v);
  194. $arr[$controller][] = $v;
  195. }
  196. }
  197. }
  198. closedir($handle);
  199. return $arr;
  200. }
  201. }
初始化类:
  1. <?php
  2. /* ---------------------------------------------------------------------------------------
  3. | 初始化控制器
  4. -----------------------------------------------------------------------------------------
  5. | 版权所有 lamp兄弟连
  6. -----------------------------------------------------------------------------------------
  7. | 作者: 李捷 (lijie@li-jie.me)
  8. | 最后修改时间: 2012-05-06 18:30
  9. -----------------------------------------------------------------------------------------
  10. */
  11. class Common extends Action {
  12. /*
  13. 初始化方法
  14. */
  15. public function init(){
  16. //如果SESSION为空,则跳转
  17. if(empty($_SESSION['user_login'])){
  18. $this->redirect("pub/index");
  19. }
  20. $a = new rbac();
  21. if(!$a->check($_SESSION['user_info']['id'])){
  22. echo "<script>alert('您没有此权限!')</script>";
  23. exit("<script>document.write('<span style=\'font-size:40px;font-weight:bold\'>Access Forbidden');alert('您没有此权限!');</script>");
  24. $this->redirect("pub/index");
  25. }
  26. }
  27. }

这里给大家写了一个简单的RBAC类,仅供大家学习参考此思想,如有问题可以跟帖回复....

欢迎拍砖哈......

更多给力文章,请挪步:
【捷哥浅谈PHP】第一弹---php位运算符”|”和逻辑运算符”||”遇到的问题
【捷哥浅谈PHP】第二弹---经典算法的运用(冒泡排序和快速排序)
【捷哥浅谈PHP】第三弹---使用二分查找法查找数组中的元素位置
【捷哥浅谈PHP】第四弹---递归函数
【捷哥浅谈PHP】第五弹 --- 分页之九阳神功
【捷哥浅谈PHP】第六弹 ---- 使用for循环输出九九乘法表
原文地址:http://bbs.lampbrother.net/read-htm-tid-118412.html
阅读(68) | 评论(0) | 转发(0) |
0

上一篇:【捷哥浅谈PHP】第七弹 ---- 基于角色的访问控制RBAC

下一篇:【大官人High帖】为粮票,大官人不再发激情照。今天是:生成字符串

相关热门文章
  • IP Sec VPN与NAT破镜重圆
  • 网站导航
  • GoAgent图文设置教程
  • UT2.0正式版下载
  • tomcat6.0配置(含配置视频下载...
  • 大家都是用什么来管理hadoop集...
  • 网站被人挂了吗,添加了些程序...
  • Nginx如何保证不走宕机的那个...
  • 大家谈谈MYSQL客户端和服务器...
  • 以下代码运行后为何会输出5?...
给主人留下些什么吧!~~
评论热议
原创粉丝点击