麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 編程 > PHP > 正文

thinkphp和onethink之權限管理

2020-03-22 19:49:18
字體:
來源:轉載
供稿:網友
  • onethink權限管理主要分為兩個方面一種菜單節點檢測,另一種是動態檢測(未實現)。
    第一次進入系統后,在Admin/Controller/AdminController.html' target='_blank'>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();//動態檢測的代碼,返回null                    if( $dynamic === null ){                        //檢測非動態權限                        $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的數據庫中有四張表是和權限管理有關聯的,這里寫圖片描述
    其中rule表對應的是此系統中所有的url生成的規則表,group表對應的是某個分組所擁有的權限,也就是某個分組可以訪問的url集合。group_access代表的某個用戶屬于某個組,extend表主要用來實現動態檢測。

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

         /**     * action訪問控制,在 **登陸成功** 后執行的第一項權限檢測任務     *     * @return boolean|null  返回值必須使用 `===` 進行判斷     *     *   返回 **false**, 不允許任何人訪問(超管除外)     *   返回 **true**, 允許任何管理員訪問,無需執行節點權限檢測     *   返回 **null**, 需要繼續執行節點權限檢測決定是否允許訪問     *      */  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;//需要檢測節點權限    }

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

        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) { #如果是多個,將其拆分成數組                $name = explode(',', $name);            } else {                $name = array($name);            }        }        $list = array(); //保存驗證通過的規則名        if ($mode=='url') {            $REQUEST = unserialize( strtolower(serialize($_REQUEST)) );        }        foreach ( $authList as $auth ) {            $query = preg_replace('/^.+?/U','',$auth);#獲得參數字符串            if ($mode=='url' && $query!=$auth ) {                parse_str($query,$param); //解析規則中的param 生成一個數組,鍵值對對應url中的鍵值對                $intersect = array_intersect_assoc($REQUEST,$param);#輸出$REQUEST 和$param的交集                $auth = preg_replace('/?.*$/U','',$auth);#此時的$auth為url路徑                if ( in_array($auth,$name) && $intersect==$param ) {  //如果節點相符且url參數滿足                    $list[] = $auth ;                }                }else if (in_array($auth , $name)){#遍歷用戶擁有的權限數組,如果某個權限存在于$name數組中,則將其放入$list數組,假設用戶擁有權限為1,2,3,4,5,                                                    #需要驗證的權限為2,6.那么會將2放入$list數組,                $list[] = $auth ;            }        }        exit;        if ($relation == 'or' and !empty($list)) {#如上個例子中,當為或時,只要$list數組不為空,既只要滿足一個權限就可以            return true;        }        $diff = array_diff($name, $list);        if ($relation == 'and' and empty($diff)) {#如上例中,當為與時,需要滿足$List數組和$name數組完全相同才可以,既$name中的權限全部存在于$auth中            return true;        }        return false;    }

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

        public function access(){        $this->updateRules();//首先執行此方法,此方法根據menu表中的數據更新rule表中的數據,具體見下方代碼        $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表,獲得主菜單數組以及子菜單數組        $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(){        //需要新增的節點必然位于$nodes        $nodes    = $this->returnNodes(false); #returnNodes查詢出表menu中的所有菜單項,生成一個二維數組,其中的一個值如下:    /*    0 => array:4 [▼     *    'title' => '文檔列表'     *  'url' => 'Admin/article/index'     *'tip' => ''     *'pid' => '2'     *    ]    */        $AuthRule = M('AuthRule');        $map      = array('module'=>'admin','type'=>array('in','1,2'));        //需要更新和刪除的節點必然位于$rules        $rules    = $AuthRule->where($map)->order('name')->select();//查詢出屬于admin模塊的所有規則,其中type=1代表url,type=2代表主菜單        //構建insert數據        $data     = array();//保存需要插入和更新的新節點        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的一個子數組如下:此時$data存儲的為menu表中的數據         *   'admin/article/indexadmin1' => array:5 [▼         *   'name' => 'Admin/article/index'         *   'title' => '文檔列表'         *   'module' => 'admin'         *   'type' => 1         *   'status' => 1          ]         */        $update = array();//保存需要更新的節點        $ids    = array();//保存需要刪除的節點的id        foreach ($rules as $index=>$rule){//$data是菜單生成的數組,此循環的作用是根據菜單數組,來進行規則表的增刪改操作,如果規則數組中的某個鍵和菜單數組的鍵相同則將菜單數組                                        //中的該值放入$updata表,將規則數組的值放入$diff表,如果規則數組中某個值不存在與菜單數組中,說明規則數組中的該值需要刪除            $key = strtolower($rule['name'].$rule['module'].$rule['type']);            if ( isset($data[$key]) ) {//如果數據庫中的規則與配置的節點匹配,說明是需要更新的節點                $data[$key]['id'] = $rule['id'];//為需要更新的節點補充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是規則表生成的            foreach ($update as $k=>$row){                if ( $row!=$diff[$row['id']] ) {//判斷菜單數組的數據是否有更新,如果有更新,規則表也進行更新                    $AuthRule->where(array('id'=>$row['id']))->save($row);                }            }        }        if ( count($ids) ) { //            $AuthRule->where( array( 'id'=>array('IN',implode(',',$ids)) ) )->save(array('status'=>-1));            //刪除規則是否需要從每個用戶組的訪問授權表中移除該規則?        }        //需要更新的$data已經unset掉,剩余的數據為為新增數據,執行add操作        if( count($data) ){            $AuthRule->addAll(array_values($data));//array_values函數將關聯數組變為索引數組,只作用的一維        }        if ( $AuthRule->getDbError() ) {            trace('['.__METHOD__.']:'.$AuthRule->getDbError());            return false;        }else{            return true;        }    }

    生成菜單數據后,view層使用三層循環將數據輸出,循環的數據如內容
    這里寫圖片描述

                    <volist name='node_list' id='node' >//第一次循環主菜單                                        <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' > //第二次循環子菜單                                                    <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']'>                                                                                                                                  <volist name='child['operator']' id='op'> //第三次循環操作                                                                       <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>                                                                                                                           </notempty>                                                        </div>                                                </volist>                                                </present>                                            </dd>                                        </dl>                                    </volist>

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

     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數組的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{//返回一維數組            $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()函數的代碼為:

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

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

    PHP編程

    鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。

  • 發表評論 共有條評論
    用戶名: 密碼:
    驗證碼: 匿名發表
    主站蜘蛛池模板: 一区二区国产在线 | 99成人精品视频 | 国产小视频在线观看 | 欧美a∨一区二区三区久久黄 | 国产精品视频1区 | 免费在线观看成人av | 国产精品观看在线亚洲人成网 | 美国av免费看 | 亚洲午夜影院在线观看 | 欧美一级电影网站 | 成人毛片100部 | 亚洲第九十九页 | 欧美黄色大片免费观看 | 毛片在哪里看 | 主播粉嫩国产在线精品 | 国产美女一区二区在线观看 | 91福利免费观看 | 九色激情网 | 97久色| 一区二区三区欧美在线观看 | 久草在线网址 | 久久精品成人免费国产片桃视频 | 亚洲精品日韩色噜噜久久五月 | 九九热九九热 | 嗯~啊~弄嗯~啊h高潮视频 | 99最新网址| 51国产偷自视频区视频小蝌蚪 | 国产精品久久久久久久午夜片 | 成年人黄色免费网站 | 青青草国产在线视频 | 亚洲国产成人久久成人52 | 久久精品亚洲一区二区 | 久久国产精品电影 | 在线播放免费av | 国产亚洲精品综合一区91 | 欧美一级黄色网 | 91短视频在线观看视频 | 污黄视频在线观看 | 欧美a∨亚洲欧美亚洲 | 一区视频| 日韩视频一二区 |