多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區(qū)平臺 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當前位置:首頁 > php開源 > php教程 > thinkphp和onethink之權限管理

thinkphp和onethink之權限管理

來源:程序員人生   發(fā)布時間:2016-06-04 08:15:26 閱讀次數(shù):2408次

onethink權限管理主要分為兩個方面1種菜單節(jié)點檢測,另外一種是動態(tài)檢測(未實現(xiàn))。
第1次進入系統(tǒng)后,在Admin/Controller/AdminController.class.php中權限驗證的代碼為:

define('IS_ROOT', is_administrator()); if(!IS_ROOT && C('ADMIN_ALLOW_IP')){ // 檢查IP地址訪問 if(!in_array(get_client_ip(),explode(',',C('ADMIN_ALLOW_IP')))){ $this->error('403:制止訪問'); } } $access = $this->accessControl(); if ( $access === false ) { $this->error('403:制止訪問'); }elseif( $access === null ){ $dynamic = $this->checkDynamic();//動態(tài)檢測的代碼,返回null if( $dynamic === null ){ //檢測非動態(tài)權限 $rule = strtolower(MODULE_NAME.'/'.CONTROLLER_NAME.'/'.ACTION_NAME); if(!IS_ROOT) { if (!$this->checkRule($rule, array('in', '1,2'))) { $this->error('未授權訪問!'); exit; } } }elseif( $dynamic === false ){ $this->error('未授權訪問!'); } }

在onethink的數(shù)據(jù)庫中有4張表是和權限管理有關聯(lián)的,這里寫圖片描述
其中rule表對應的是此系統(tǒng)中所有的url生成的規(guī)則表,group表對應的是某個分組所具有的權限,也就是某個分組可以訪問的url集合。group_access代表的某個用戶屬于某個組,extend表主要用來實現(xiàn)動態(tài)檢測。

/Admin/Controller/AdminController.class.php中進行的第1次權限檢測,

/** * action訪問控制,在 **登陸成功** 后履行的第1項權限檢測任務 * * @return boolean|null 返回值必須使用 `===` 進行判斷 * * 返回 **false**, 不允許任何人訪問(超管除外) * 返回 **true**, 允許任何管理員訪問,無需履行節(jié)點權限檢測 * 返回 **null**, 需要繼續(xù)履行節(jié)點權限檢測決定是不是允許訪問 * */ final protected function accessControl(){ $allow = C('ALLOW_VISIT'); $deny = C('DENY_VISIT');#這兩項配置存儲在config表中 $check = strtolower(CONTROLLER_NAME.'/'.ACTION_NAME); if ( !empty($deny) && in_array_case($check,$deny) ) { return false;//非超管制止訪問deny中的方法 } if ( !empty($allow) && in_array_case($check,$allow) ) { return true; } return null;//需要檢測節(jié)點權限 }

權限認證的配置在/ThinkPHP/Library/Think/Auth.class.php中如圖:
這里寫圖片描述
規(guī)則驗證中最重要的函數(shù)為check()函數(shù):

public function check($name, $uid, $type=1, $mode='url', $relation='or') { if (!$this->_config['AUTH_ON'])#如果沒有開啟驗證,返回true return true; $authList = $this->getAuthList($uid,$type); //獲得用戶具有的權限列表 if (is_string($name)) { $name = strtolower($name); if (strpos($name, ',') !== false) { #如果是多個,將其拆分成數(shù)組 $name = explode(',', $name); } else { $name = array($name); } } $list = array(); //保存驗證通過的規(guī)則名 if ($mode=='url') { $REQUEST = unserialize( strtolower(serialize($_REQUEST)) ); } foreach ( $authList as $auth ) { $query = preg_replace('/^.+\?/U','',$auth);#取得參數(shù)字符串 if ($mode=='url' && $query!=$auth ) { parse_str($query,$param); //解析規(guī)則中的param 生成1個數(shù)組,鍵值對對應url中的鍵值對 $intersect = array_intersect_assoc($REQUEST,$param);#輸出$REQUEST 和$param的交集 $auth = preg_replace('/\?.*$/U','',$auth);#此時的$auth為url路徑 if ( in_array($auth,$name) && $intersect==$param ) { //如果節(jié)點符合且url參數(shù)滿足 $list[] = $auth ; } }else if (in_array($auth , $name)){#遍歷用戶具有的權限數(shù)組,如果某個權限存在于$name數(shù)組中,則將其放入$list數(shù)組,假定用戶具有權限為1,2,3,4,5, #需要驗證的權限為2,6.那末會將2放入$list數(shù)組, $list[] = $auth ; } } exit; if ($relation == 'or' and !empty($list)) {#如上個例子中,當為或時,只要$list數(shù)組不為空,既只要滿足1個權限就能夠 return true; } $diff = array_diff($name, $list); if ($relation == 'and' and empty($diff)) {#如上例中,當為與時,需要滿足$List數(shù)組和$name數(shù)組完全相同才可以,既$name中的權限全部存在于$auth中 return true; } return false; }

由于后臺的控制器都繼承了AdminController控制器,所以每打開1個url,都會首先檢測改用戶是不是具有權限。
進入后臺后,進入到用戶的權限管理頁面,如默許用戶組,履行的方法為:

public function access(){ $this->updateRules();//首先履行此方法,此方法根據(jù)menu表中的數(shù)據(jù)更新rule表中的數(shù)據(jù),具體見下方代碼 $auth_group = M('AuthGroup')->where( array('status'=>array('egt','0'),'module'=>'admin','type'=>AuthGroupModel::TYPE_ADMIN) ) ->getfield('id,id,title,rules'); $node_list = $this->returnNodes();//查詢menu表,取得主菜單數(shù)組和子菜單數(shù)組 $map = array('module'=>'admin','type'=>AuthRuleModel::RULE_MAIN,'status'=>1); $main_rules = M('AuthRule')->where($map)->getField('name,id');//查詢rule表取得主菜單的url和id值 $map = array('module'=>'admin','type'=>AuthRuleModel::RULE_URL,'status'=>1); $child_rules = M('AuthRule')->where($map)->getField('name,id');//查詢rule表取得子菜單的url和id值 $this->assign('main_rules', $main_rules); $this->assign('auth_rules', $child_rules); $this->assign('node_list', $node_list); $this->assign('auth_group', $auth_group); $this->assign('this_group', $auth_group[(int)$_GET['group_id']]);//當前用戶組 $this->meta_title = '訪問授權'; $this->display('managergroup'); }
public function updateRules(){ //需要新增的節(jié)點必定位于$nodes $nodes = $this->returnNodes(false); #returnNodes查詢出表menu中的所有菜單項,生成1個2維數(shù)組,其中的1個值以下: /* 0 => array:4 [▼ * "title" => "文檔列表" * "url" => "Admin/article/index" *"tip" => "" *"pid" => "2" * ] */ $AuthRule = M('AuthRule'); $map = array('module'=>'admin','type'=>array('in','1,2')); //需要更新和刪除的節(jié)點必定位于$rules $rules = $AuthRule->where($map)->order('name')->select();//查詢出屬于admin模塊的所有規(guī)則,其中type=1代表url,type=2代表主菜單 //構建insert數(shù)據(jù) $data = array();//保存需要插入和更新的新節(jié)點 foreach ($nodes as $value){ $temp['name'] = $value['url']; $temp['title'] = $value['title']; $temp['module'] = 'admin'; if($value['pid'] >0){ $temp['type'] = AuthRuleModel::RULE_URL;//RULE_URL為1代表url }else{ $temp['type'] = AuthRuleModel::RULE_MAIN;//RULE_MAIN為2代表主菜單 } $temp['status'] = 1; $data[strtolower($temp['name'].$temp['module'].$temp['type'])] = $temp;//去除重復項 } /*$data的1個子數(shù)組以下:此時$data存儲的為menu表中的數(shù)據(jù) * "admin/article/indexadmin1" => array:5 [▼ * "name" => "Admin/article/index" * "title" => "文檔列表" * "module" => "admin" * "type" => 1 * "status" => 1 ] */ $update = array();//保存需要更新的節(jié)點 $ids = array();//保存需要刪除的節(jié)點的id foreach ($rules as $index=>$rule){//$data是菜單生成的數(shù)組,此循環(huán)的作用是根據(jù)菜單數(shù)組,來進行規(guī)則表的增刪改操作,如果規(guī)則數(shù)組中的某個鍵和菜單數(shù)組的鍵相同則將菜單數(shù)組 //中的該值放入$updata表,將規(guī)則數(shù)組的值放入$diff表,如果規(guī)則數(shù)組中某個值不存在與菜單數(shù)組中,說明規(guī)則數(shù)組中的該值需要刪除 $key = strtolower($rule['name'].$rule['module'].$rule['type']); if ( isset($data[$key]) ) {//如果數(shù)據(jù)庫中的規(guī)則與配置的節(jié)點匹配,說明是需要更新的節(jié)點 $data[$key]['id'] = $rule['id'];//為需要更新的節(jié)點補充id值 $update[] = $data[$key]; unset($data[$key]); unset($rules[$index]); unset($rule['condition']); $diff[$rule['id']]=$rule; }elseif($rule['status']==1){ $ids[] = $rule['id']; } } if ( count($update) ) { //$update是菜單表生成的,$diff是規(guī)則表生成的 foreach ($update as $k=>$row){ if ( $row!=$diff[$row['id']] ) {//判斷菜單數(shù)組的數(shù)據(jù)是不是有更新,如果有更新,規(guī)則表也進行更新 $AuthRule->where(array('id'=>$row['id']))->save($row); } } } if ( count($ids) ) { // $AuthRule->where( array( 'id'=>array('IN',implode(',',$ids)) ) )->save(array('status'=>-1)); //刪除規(guī)則是不是需要從每一個用戶組的訪問授權表中移除該規(guī)則? } //需要更新的$data已unset掉,剩余的數(shù)據(jù)為為新增數(shù)據(jù),履行add操作 if( count($data) ){ $AuthRule->addAll(array_values($data));//array_values函數(shù)將關聯(lián)數(shù)組變成索引數(shù)組,只作用的1維 } if ( $AuthRule->getDbError() ) { trace('['.__METHOD__.']:'.$AuthRule->getDbError()); return false; }else{ return true; } }

生成菜單數(shù)據(jù)后,view層使用3層循環(huán)將數(shù)據(jù)輸出,循環(huán)的數(shù)據(jù)如內容
這里寫圖片描述

<volist name="node_list" id="node" >//第1次循環(huán)主菜單 <dl class="checkmod"> <dt class="hd"> <label class="checkbox"><input class="auth_rules rules_all" type="checkbox" name="rules[]" value="<?php echo $main_rules[$node['url']] ?>">{$node.title}管理</label> </dt> <dd class="bd"> <present name="node['child']"> <volist name="node['child']" id="child" > //第2次循環(huán)子菜單 <div class="rule_check"> <div> <label class="checkbox" <notempty name="child['tip']">title='{$child.tip}'</notempty>> <input class="auth_rules rules_row" type="checkbox" name="rules[]" value="<?php echo $auth_rules[$child['url']] ?>"/>{$child.title} </label> </div> <notempty name="child['operator']"> <span class="child_row"> <volist name="child['operator']" id="op"> //第3次循環(huán)操作 <label class="checkbox" <notempty name="op['tip']">title='{$op.tip}'</notempty>> <input class="auth_rules" type="checkbox" name="rules[]" value="<?php echo $auth_rules[$op['url']] ?>"/>{$op.title} </label> </volist> </span> </notempty> </div> </volist> </present> </dd> </dl> </volist>

對如何生成菜單數(shù)據(jù)主要調用了兩個函數(shù)為:returnNodes()和函數(shù)list_to_tree(),
returnNodes()函數(shù)的代碼為:

final protected function returnNodes($tree = true){ static $tree_nodes = array(); if ( $tree && !empty($tree_nodes[(int)$tree]) ) { return $tree_nodes[$tree]; } if((int)$tree){ $list = M('Menu')->field('id,pid,title,url,tip,hide')->order('sort asc')->select(); foreach ($list as $key => $value) { //給$list數(shù)組的url字段加上模塊名 if( stripos($value['url'],MODULE_NAME)!==0 ){ $list[$key]['url'] = MODULE_NAME.'/'.$value['url']; } } $nodes = list_to_tree($list,$pk='id',$pid='pid',$child='operator',$root=0);//將菜單生成樹形結構 foreach ($nodes as $key => $value) { if(!empty($value['operator'])){ $nodes[$key]['child'] = $value['operator'];//將鍵名由operator更改成child unset($nodes[$key]['operator']); } } }else{//返回1維數(shù)組 $nodes = M('Menu')->field('title,url,tip,pid')->order('sort asc')->select(); foreach ($nodes as $key => $value) { if( stripos($value['url'],MODULE_NAME)!==0 ){ $nodes[$key]['url'] = MODULE_NAME.'/'.$value['url']; } } } $tree_nodes[(int)$tree] = $nodes; return $nodes; }

list_to_tree()函數(shù)的代碼為:

function list_to_tree($list, $pk='id', $pid = 'pid', $child = '_child', $root = 0) { // 創(chuàng)建Tree $tree = array(); if(is_array($list)) { // 創(chuàng)建基于主鍵的數(shù)組援用 $refer = array(); foreach ($list as $key => $data) { $refer[$data[$pk]] = & $list[$key];//將$list數(shù)組以援用的方式轉換成$refer數(shù)組,鍵為子數(shù)組的id值 } foreach ($list as $key => $data) { // 判斷是不是存在parent $parentId = $data[$pid]; if ($root == $parentId) {//此時pid = 0為主菜單,直接放入$tree數(shù)組 $tree[] =& $list[$key]; }else{ if (isset($refer[$parentId])) {//此時當前url的父菜單在$refer中 $parent =& $refer[$parentId]; $parent[$child][] =& $list[$key]; // dump($parent); } } } } return $tree; }

這里寫圖片描述
函數(shù)list_to_tree()僅使用的幾行代碼就生成了1個樹,現(xiàn)分析以下 :
$parent =& $refer[$parentId]是以援用的方式賦值,所以改變$parent的值,就相當于改變$refer的值,又由于 $refer[$data[$pk]] = $list[$key], 所以改變$refer的值就相當于改變$list的值,又由于$tree[] =& $list[$key]所以改變$list的值就相當于改變$tree的值,總結為:改變了$parent的值就相當于改變了$tree的值,以上圖為例,它是生成的樹形結構中的用戶分類,當遍歷到用戶信息時,在$refer中含有用戶這個數(shù)組,所以會在用戶這個數(shù)組中添加1個子元素,鍵為operator,值為用戶信息這個數(shù)組,當遍歷到新增用戶時,一樣查找$refer,在$refer這個數(shù)組中含有用戶信息這個數(shù)組,所以給用戶信息這個數(shù)組添加1個子元素,鍵為operator,值為新增用戶這個數(shù)組,由于使用援用的關系,所以$tree數(shù)組的每個元素都是到此函數(shù)履行到最后1步才肯定的,比如當用戶信息添加了子元素新增用戶時,用戶這個數(shù)組也會隨著進行變動。

生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 国产一级性片 | 欧美不卡一区二区三区 | 爽爽影院色黄网站在线观看 | 免费伦理片在线观看 | 精品无码久久久久久国产 | 欧美成人综合 | 国产欧美精品国产国产专区 | 欧美一级aa天码毛片 | 精品国产理论在线观看不卡 | 黑人群姣中国妞在线观看 | 国产69精品久久久久妇女 | 国产美女福利视频福利 | 67194在线午夜亚洲 | 免费观看性欧美特黄 | 亚洲国产精品ⅴa在线观看 亚洲国产精品aaa一区 | 亚洲欧洲精品国产二码 | 999毛片免费 | 在线成人亚洲 | 日本成人不卡视频 | 国产永久一区二区三区 | 国产精品视频久久 | 99精品国产美女福到在线不卡 | 欧美成人h版整片合集 | 日韩精品欧美一区二区三区 | 无国产精品白浆免费视 | 中文字幕一区二区三区四区五区 | www.男女| 婷婷五月在线视频 | 欧美特级淫片 | 在线看欧美成人中文字幕视频 | 操操网址 | 亚洲视屏在线观看 | 国产四区 | 中文精品99久久国产 | 九月丁香激情综合婷婷玉立 | 欧美一区二区三区香蕉视 | 日韩欧美伊人久久大香线蕉 | 亚洲欧美小说 | 欧美精品一区二区三区久久 | ww在线观视频免费观看 | 成人国产在线视频在线观看 |