我的一些個人理解,還是有些不懂的地方,有錯誤請指正,謝謝!!!
class Auth{ //默認配置 protected $_config = array( 'auth_on' => true, // 認證開關 'auth_type' => 1, // 認證方式,1為實時認證;2為登錄認證。 'auth_group' => 'auth_group', // 用戶組數據表名 'auth_group_access' =>'auth_group_access', // 用戶-用戶組關系表 'auth_rule' => 'auth_rule', // 權限規則表 'auth_user' => 'member' // 用戶信息表 ); public function __construct() { if (config('auth_config')) { //可設置配置項 auth_config, 此配置項為數組。 $this->_config = array_merge($this->_config, config('auth_config')); //不知道config('auth_config')在哪里配置,有什么參數? } } /** * 檢查權限 * @param name string|array 需要驗證的規則列表,支持逗號分隔的權限規則或索引數組 * @param uid int 認證用戶的id * @param string mode 執行check的模式 * @param relation string 如果為 'or' 表示滿足任一條規則即通過驗證;如果為 'and'則表示需滿足所有規則才能通過驗證 * @return boolean 通過驗證返回true;失敗返回false */ public function check($name, $uid, $type=1, $mode='url', $relation='or') { if (!$this->_config['auth_on']) return true; //小寫的組下全部權限名稱name(一維數組) $authList = $this->getAuthList($uid,$type); //獲取用戶需要驗證的所有有效規則列表 /*array( [0] =>controller/funtion,[1] => controller/funtion,[2]...... ) */ //判斷name是什么類型,並 全部轉化成array類型 if (is_string($name)) { $name = strtolower($name);//轉小寫 if (strpos($name, ',') !== false) {//查找 "," 在字符串中第一次出現的位置:返回數字 $name = explode(',', $name);//一維數組 } else { $name = array($name);//一維數組 } // $name = strpos($name, ',') !== false ? explode(',', $name) : [$name]; } $list = array(); //保存驗證通過的規則名 if ($mode=='url') { //serialize() 返回字符串,此字符串包含了表示 value 的字節流,可以存儲於任何地方。 //strtolower:把所有字符轉換為小寫: //unserialize:從已存儲的表示中創建 PHP 的值 $REQUEST = unserialize( strtolower(serialize($_REQUEST)) ); } //兩種種比較方法!!! //if ($mode=='url' && $query!=$auth ) 節點相符且url參數滿足 //in_array($auth , $name) name在auth存在對應 foreach ( $authList as $auth ) { $query = preg_replace('/^.+\?/U','',$auth); if ($mode=='url' && $query!=$auth ) { //當賦予的權限和url上的路徑不一樣的時候的做法 // //把查詢字符串解析到變量中: parse_str($query,$param); //解析規則中的param /*$param = array(1) { ["controller/index"] => string(0) "" }*/ //array_intersect_assoc比較兩個數組的鍵名和鍵值,並返回交集: $intersect = array_intersect_assoc($REQUEST,$param); $auth = preg_replace('/\?.*$/U','',$auth); if ( in_array($auth,$name) && $intersect==$param ) { //如果節點相符且url參數滿足 $list[] = $auth ; } }else if (in_array($auth , $name)){ $list[] = $auth ; } } // or 和 and if ($relation == 'or' and !empty($list)) { return true; } //比較兩個數組的鍵值,並返回差集: $diff = array_diff($name, $list);//返回都沒有的值 if ($relation == 'and' and empty($diff)) { return true; } return false; } /** * 根據用戶id獲取用戶組,返回值為數組 * @param uid int 用戶id * @return array 用戶所屬的用戶組 array( * array('uid'=>'用戶id','group_id'=>'用戶組id','title'=>'用戶組名稱','rules'=>'用戶組擁有的規則id,多個,號隔開'), * ...) */ public function getGroups($uid) { static $groups = array(); //靜態,使用第二次直接返回就行 if (isset($groups[$uid])) return $groups[$uid]; $user_groups = \think\Db::name($this->_config['auth_group_access'])//用戶-用戶組關系表 ->alias('a') ->join($this->_config['auth_group']." g", "g.id=a.group_id")//用戶組數據表名 ->where("a.uid='$uid' and g.status='1'") ->field('uid,group_id,title,rules')->select(); /*$user_groups = Db::view($this->config['auth_group_access'], 'uid,group_id') ->view($this->config['auth_group'], 'title,rules', "{$this->config['auth_group_access']}.group_id={$this->config['auth_group']}.id") ->where(['uid' => $uid, 'status' => 1])->select();*/ $groups[$uid] = $user_groups ? $user_groups : array(); return $groups[$uid]; } /** * 獲得權限列表 * @param integer $uid 用戶id * @param integer $type * @param $_SESSION['_auth_list_'.$uid.$t] = $_authList[$uid.$t] = 權限($name(array))一維數組 array( [0] =>controller/funtion,[1] => controller/funtion,[2]...... ) */ protected function getAuthList($uid,$type) { static $_authList = array(); //保存用戶驗證通過的權限列表 //implode: 把數組元素組合為字符串 $t = implode(',',(array)$type);//1 if (isset($_authList[$uid.$t])) {// 已經獲取到權限name的 直接返回 return $_authList[$uid.$t]; } //登錄才需要用到的判斷 if( $this->_config['auth_type']==2 && isset($_SESSION['_auth_list_'.$uid.$t])){//1 && _auth_list_241 return $_SESSION['_auth_list_'.$uid.$t]; } //讀取用戶所屬用戶組 'uid,group_id,title,rules(字符串,權限id)'二維數組,其實只要一組數據而已【0】 $groups = $this->getGroups($uid); $ids = array();//保存用戶所屬用戶組設置的所有權限規則id foreach ($groups as $g) { //trim: 移除字符串左側的字符 //explode: 把字符串打散為數組 $ids = array_merge($ids, explode(',', trim($g['rules'], ',')));//一維數組 } //array_unique: 移除數組中重復的值 $ids = array_unique($ids); //如果沒有權限就返回一個空數組 if (empty($ids)) { $_authList[$uid.$t] = array(); return array(); } $map=array( 'id'=>array('in',$ids), 'type'=>$type, 'status'=>1, ); //讀取用戶組所有權限規則 $rules = \think\Db::name($this->_config['auth_rule'])->where($map)->field('condition,name')->select();//二維數組 /* * array(3) { [0] => array(2) { ["condition"] => string(0) "" ["name"] => string(8) "conf/add" } [1] => array(2) { ["condition"] => string(0) "" ["name"] => string(8) "conf/del" } [2] => array(2) { ["condition"] => string(0) "" ["name"] => string(8) "link/del" } } * */ //循環規則,判斷結果。 $authList = array(); // foreach ($rules as $rule) { if (!empty($rule['condition'])) { //根據condition進行驗證 $user = $this->getUserInfo($uid);//獲取用戶全部信息,一維數組 //preg_replace:替一個正則表達式的搜索和替換, 參數一:搜索,參數二:替換,參數三:要搜索替換的目標字符串或字符串數組 //試了一下,不知道有什么用,$rule['condition']是什么,輸出的也一樣,沒變! //我覺得那個condition就是在這里用正則判斷的 $command = preg_replace('/\{(\w*?)\}/', '$user[\'\\1\']', $rule['condition']); //dump($command);//debug //eval() 函數把字符串按照 PHP 代碼來計算。 //$$command是什么,$condition就是什么,輸出的也一樣,沒變! @(eval('$condition=(' . $command . ');')); if ($condition) { //strtolower: 把所有字符轉換為小寫: $authList[] = strtolower($rule['name']);//小寫的組下全部權限名稱(一維數組) } } else { //只要存在就記錄 $authList[] = strtolower($rule['name']); } } $_authList[$uid.$t] = $authList; if($this->_config['auth_type']==2){ //規則列表結果保存到session $_SESSION['_auth_list_'.$uid.$t]=$authList; } return array_unique($authList); } /** * 獲得用戶資料,根據自己的情況讀取數據庫 */ protected function getUserInfo($uid) { static $userinfo=array(); if(!isset($userinfo[$uid])){ $userinfo[$uid]=\think\Db::name($this->_config['auth_user'])->where(array('uid'=>$uid))->find(); } return $userinfo[$uid]; } }
對那個 登錄認證 還是不是很懂!!!
