<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                有一個網友問,有權限嗎?我之前也說了,會加上權限。一直很忙,沒有去添加。今天就來更新一下,如何在 thinkphp5 框架中實現權限的控制。 主流的權限控制有 rbac 和 auth 。我先來介紹一下 rbac,然后在此基礎之上,再介紹一下 auth 的實現。 rbac 這個系統的設計,就拿我之前開源的系統來講解吧。正好,那個系統實現的就是 rbac 。你可以到這個地址[github 上的 snake](https://github.com/nick-bai/snake),或者直接到源碼下載那一章節下載我演示的代碼。 rbac 中文名 叫 角色權限控制,具體的什么解釋,你可以自行百度,比我解釋的專業。這里,我只是想說明一下,設計 rabc 權限的思路。首先我們的系統必須擁有的表有如下幾張: 1、用戶表 這個是必須的,因為系統需要用戶的登錄,這是不可或缺的。 2、節點表 記錄著系統中的各個操作節點,方便我們通過這些節點去拼裝菜單,以及權限的分配。 > 所謂的節點,在 rbac 中你可以理解成:模塊、控制器、方法。這些對應的名字。 3、角色表 存放各種系統的角色。 這幾張表有了。講一下,具體的實現方式。 > 我們 通過 給角色分配一些操作節點的權限,然后再給 用戶 指定角色。這樣,當用戶當用戶操作某個 控制器\\方法 的時候,我們檢測他所屬的角色,是否有這個 節點的規則,就能判斷,他是否可以操作這個 方法。 講到 auth 可以理解成加強版的 rbac,他不僅可以驗證節點,同樣還可以比 rbac 驗證更多的小細節。比如,某個節點,必須要 積分 > 500 的才能操作,因為 rabc 只能控制節點(這個節點就是由 模塊\\控制器\\方法名 組成的字串),無法驗證別的小細節。而 auth 是驗證 規則的,而不是節點。 > 遺憾的是,目前能找到的一些介紹 auth 的 thinkphp 代碼,其實就是 rbac,并沒有展示 auth 比 rbac 好的地方。另外,其實你做一個 auth 權限系統,也并不一定要官方的那個 auth 類,這個類 thinkphp5 官方暫時未提供。其實你要是理解原理之后,很容易寫出和你的系統化完全匹配的 auth 方法來。 在我們做 rbac 的時候,錄入的節點是按照 模塊、控制器、方法名,這樣的順序錄入到 節點表中的,而在我們驗證權限的時候,又得將這些 模塊、控制器、方法名拼接成字符串。 比如:我們在表中錄入 index 、shop、addShop 這三個節點,而我們在 驗證的時候,會驗證 index/shop/addshop,這樣去驗證,而我拼裝成的這個樣子的 字串**index/shop/addshop**就是 auth 中所講的 規則。其實,我們在 rbac 權限系統中,去分開錄入 這樣三個 字段,不如直接錄入像 auth 這樣的規則。反而更利于我們的后續操作。 說到這里,有沒有發現,其實 rbac 和 auth 是很像的,這也就是為什么,很多的所謂的講 auth 的代碼,都是“掛羊頭賣狗肉”的rbac。其實,我們只要在 節點表 (auth 中稱為規則表)中,加入一個 附件條件 字段,在驗證規則的同是,去檢測 附加條件 是否滿足,從而實現更加細節的驗證。至于這個附加條件,你怎么去設計。你可以按照官方的那種方式去設計,也可以自己去 設計這個填寫格式,反正你自己能有辦法解析就行。 我們在正式開始寫 auth 系統之前,先來看看,我們需要設計哪些表。 1、用戶表 ~~~ -- ---------------------------- -- Table structure for auth_user -- ---------------------------- DROP TABLE IF EXISTS `auth_user`; CREATE TABLE `auth_user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(255) COLLATE utf8_bin DEFAULT '' COMMENT '用戶名', `password` varchar(255) COLLATE utf8_bin DEFAULT '' COMMENT '密碼', `loginnum` int(11) DEFAULT '0' COMMENT '登陸次數', `last_login_ip` varchar(255) COLLATE utf8_bin DEFAULT '' COMMENT '最后登錄IP', `last_login_time` int(11) DEFAULT '0' COMMENT '最后登錄時間', `real_name` varchar(255) COLLATE utf8_bin DEFAULT '' COMMENT '真實姓名', `status` int(1) DEFAULT '0' COMMENT '狀態', `roleid` int(11) DEFAULT '1' COMMENT '用戶角色id', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_bin; -- ---------------------------- -- Records of auth_user -- ---------------------------- INSERT INTO `auth_user` VALUES ('1', 'admin', '21232f297a57a5a743894a0e4a801fc3', '32', '127.0.0.1', '1490852367', 'admin', '1', '1'); INSERT INTO `auth_user` VALUES ('2', 'xiaobai', '4297f44b13955235245b2497399d7a93', '6', '127.0.0.1', '1470368260', '小白', '1', '2'); ~~~ 2、角色表 (在 auth 中稱之為 權限組 其實是一個概念) ~~~ -- ---------------------------- -- Table structure for auth_role -- ---------------------------- DROP TABLE IF EXISTS `auth_role`; CREATE TABLE `auth_role` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id', `rolename` varchar(155) NOT NULL COMMENT '角色名稱', `rule` varchar(255) DEFAULT '' COMMENT '權限節點數據', PRIMARY KEY (`id`) ) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of auth_role -- ---------------------------- INSERT INTO `auth_role` VALUES ('1', '超級管理員', ''); INSERT INTO `auth_role` VALUES ('2', '系統維護員', '1,2,3,4,5,6,7,8,9,10'); INSERT INTO `auth_role` VALUES ('3', '新聞發布員', '1,2,3,4,5'); ~~~ 3、規則表 ~~~ -- ---------------------------- -- Table structure for auth_node -- ---------------------------- DROP TABLE IF EXISTS `auth_node`; CREATE TABLE `auth_node` ( `id` int(11) NOT NULL AUTO_INCREMENT, `node_name` varchar(155) NOT NULL DEFAULT '' COMMENT '節點名稱', `rule` varchar(155) NOT NULL COMMENT '權限規則', `is_menu` tinyint(1) NOT NULL DEFAULT '1' COMMENT '是否是菜單項 1不是 2是', `typeid` int(11) NOT NULL COMMENT '父級節點id', `style` varchar(155) DEFAULT '' COMMENT '菜單樣式', `condition` varchar(155) DEFAULT NULL COMMENT '附加條件', PRIMARY KEY (`id`) ) ENGINE=MyISAM AUTO_INCREMENT=15 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of auth_node -- ---------------------------- INSERT INTO `auth_node` VALUES ('1', '用戶管理', '#', '2', '0', 'fa fa-users', null); INSERT INTO `auth_node` VALUES ('2', '用戶列表', 'user/index', '2', '1', '', null); INSERT INTO `auth_node` VALUES ('3', '添加用戶', 'user/useradd', '1', '2', '', null); INSERT INTO `auth_node` VALUES ('4', '編輯用戶', 'user/useredit', '1', '2', '', null); INSERT INTO `auth_node` VALUES ('5', '刪除用戶', 'user/userdel', '1', '2', '', null); INSERT INTO `auth_node` VALUES ('6', '角色列表', 'role/index', '2', '1', '', null); INSERT INTO `auth_node` VALUES ('7', '添加角色', 'role/roleadd', '1', '6', '', null); INSERT INTO `auth_node` VALUES ('8', '編輯角色', 'role/roleedit', '1', '6', '', null); INSERT INTO `auth_node` VALUES ('9', '刪除角色', 'role/roledel', '1', '6', '', null); INSERT INTO `auth_node` VALUES ('10', '分配權限', 'role/giveaccess', '1', '6', '', null); INSERT INTO `auth_node` VALUES ('11', '系統管理', '#', '2', '0', 'fa fa-desktop', null); INSERT INTO `auth_node` VALUES ('12', '數據備份/還原', 'data/index', '2', '11', '', null); INSERT INTO `auth_node` VALUES ('13', '備份數據', 'data/importdata', '1', '12', '', null); INSERT INTO `auth_node` VALUES ('14', '還原數據', 'data/backdata', '1', '12', '', null); ~~~ > 關于系統的管理員登錄、角色的增刪改查、規則的增刪改查、用戶的增刪改查等,這些基礎的功能,在本部分不做過多的介紹。相信你通過前面的,用戶的增刪改查,已經會用 thinkphp5 完成 CURD 的操作了。本初只重點介紹,權限系統的具體起作用的部分。 ## 從登陸開始講起 登錄的基礎功能,校驗用戶名,密碼,驗證碼這些內容,代碼中都有,此處不做過多的介紹。開始看看,我們在登陸的時候,應該做哪些權限的工作。 確認用戶一切信息正確之后,我做了如下的操作 Login.php ~~~ //獲取該管理員的角色信息 $user = new UserType(); $info = $user->getRoleInfo($hasUser['roleid']); ~~~ 根據用戶的 角色id 去獲取用戶所擁有的 權限信息。我在用戶表中設置了一個 rule 的字段,這個字段以逗號隔開,存儲著用戶的權限節點的 id。例如 rule 字段的結果是 1,2 。 那么對應的節點就是 # 和 user/index 也就是擁有,用戶列表查看的權限。我們拿著用戶的權限 rule 去 node 表中把他擁有的 權限節點數據全部查出。 Usertype.php ~~~ /** * 獲取角色信息 * @param $id */ public function getRoleInfo($id){ $result = db('role')->where('id', $id)->find(); if(empty($result['rule'])){ $where = ''; }else{ $where = 'id in('.$result['rule'].')'; } $res = db('node')->field('rule')->where($where)->select(); foreach($res as $key=>$vo){ if('#' != $vo['rule']){ $result['action'][] = $vo['rule']; } } return $result; } ~~~ > 我們在此處設計的是 超級管理員的 rule 是空,以此來標識他是超級管理員,超級管理員擁有全部的權限。 查詢出全部的節點,把這些節點,存儲到 session 中,這樣我們就不需要每次都去查取用戶的權限節點,提高效率。 ~~~ session('username', $username); session('id', $hasUser['id']); session('role', $info['rolename']); //角色名 session('action', $info['action']); //角色權限 ~~~ action 節點的數據如下: ~~~ Array ( [0] => user/index [1] => user/useradd [2] => user/useredit [3] => user/userdel [4] => role/index [5] => role/roleadd [6] => role/roleedit [7] => role/roledel [8] => role/giveaccess [9] => data/index [10] => data/importdata [11] => data/backdata ) ~~~ 用戶擁有的節點,就放在這樣的數組里面。這樣,當用戶操作某一個節點時候,直接判斷所操作的節點是否在這個數組中即可。這些都是后面的話了,我們接著看,login 之后操作了哪些。 登錄成功之后,跳轉到 index/index 控制器,而 index 控制器,又繼承了 Base.php 這個基類,這個基類中,我們可以做一些全局的檢測。 ## 權限檢測 Base.php 我們來看一下,Base.php 做了哪些操作 ~~~ public function _initialize() { if(empty(session('username'))){ $this->redirect(url('login/index')); } //檢測權限 $canDo = authCheck(); if(!$canDo){ $this->error('沒有權限'); } //獲取權限菜單 $node = new Node(); $this->assign([ 'username' => session('username'), 'menu' => $node->getMenu(session('rule')), 'rolename' => session('role') ]); } ~~~ 用戶未登錄,跳轉到登錄。如果用戶登錄成功了,此時我們進行權限的檢測。auCheck(),定義在 common.php 中 ~~~ function authCheck(){ $control = lcfirst(request()->controller()); $action = lcfirst(request()->action()); //跳過登錄系列的檢測以及主頁權限 if(!in_array($control, ['login', 'index'])){ if(!in_array($control . '/' . $action, session('action'))){ return false; } } return true; } ~~~ 此處我們只是做了節點的驗證,你可以理解成目前還是 rbac 也就是市面上絕大多數的 所謂的 rbac 就只是檢測到這一步。很簡單,拼接現在的操作節點字串,是否在該用戶所在的權限數組中就可以了。不在,提示無權限。 最后,比較主要的步驟,根據用戶的權限節點,拼接出用戶擁有的 左側操作菜單。getMenu() ~~~ /** * 根據節點數據獲取對應的菜單 * @param $nodeStr */ public function getMenu($nodeStr = '') { //超級管理員沒有節點數組 $where = empty($nodeStr) ? 'is_menu = 2' : 'is_menu = 2 and id in('.$nodeStr.')'; $result = db('node')->field('id,node_name,typeid,rule,style') ->where($where)->select(); $menu = prepareMenu($result); return $menu; } ~~~ 這里又調用了 定義在 common.php 中的 prepareMenu() 方法 ~~~ /** * 整理菜單住方法 * @param $param * @return array */ function prepareMenu($param) { $parent = []; //父類 $child = []; //子類 foreach($param as $key=>$vo){ if($vo['typeid'] == 0){ $vo['href'] = '#'; $parent[] = $vo; }else{ $vo['href'] = url($vo['rule']); //跳轉地址 $child[] = $vo; } } foreach($parent as $key=>$vo){ foreach($child as $k=>$v){ if($v['typeid'] == $vo['id']){ $parent[$key]['child'][] = $v; } } } unset($child); return $parent; } ~~~ 我們只要在頁面中,對應的位置,渲染出這個整理更好的菜單,就可以完成操作欄,根據不同的權限,顯示不同的菜單了。 至此, rbac 部分算是結束了。 上一章的結尾,我說的是至此,rbac 的部分結束了。有人可能感覺很奇怪,不是說講的是 auth 嗎,怎么又 rbac 了。其實,你可以把 auth 理解成 rbac 的加強版。一個 auth 權限系統,首先要有 rbac 的功能。接下來才是,其區別于 rbac 的重點所在。也是 絕大部分所謂的 auth 權限系統未提及的部分。 > 我在這個文檔中講解的 auth 權限,并沒有用到 thinkphp 3.2 中給到的 auth 類,如果你想找通過改 3.2 那個類而來的 auth 權限系統。那你可能要失望了,不是我不會改那個類,而是我覺得,你懂了原理之后,根本沒必要拘泥于那個類,完全可以自己定義。 **如何正我們的 rbac 基礎之上,改成 auth 呢?** auth 區別于 rabc 的主要點是,auth 檢測的是規則,而規則我們已經有了,那就是 node 表中的 rule 字段,其實就是節點的標識。另外一點, auth 系統中通常會在 節點后面加一個 condition 字段,以此來標識,想要擁有這個權限,你還應該有哪些額外的條件。而這個條件的填寫和解析是最為關鍵的點。 ## 開始修改 首先,我們要制定一個額外的條件規則,本處為了解析的方便,以及展示原理的原則,我設計一個簡單的條件規則 ~~~ user|id={uid} and loginnum > 20 ~~~ 條件牽扯的表|條件字段=當前用戶id and 條件字段 > 20 這個語句的意思就是 某個權限的需要滿足這個用戶在 user 表中登錄的次數大于 20 才能有權限。 從之前的我展示的數據可以看到,管理員的登錄次數是 30多次。那我們就以這個例子進行講解。首先在 添加用戶 這個權限字段,也就是 node 表中的第三條 添加一個 condition 字段值 user|id={uid} and loginnum>200,也就是規定,useradd 操作的額外權限是 操作次數必須大于 200 次的才可以。此時我們看看,用戶是否有添加用戶的權限 ![](https://box.kancloud.cn/9ac0e0d8f5c07c51e84e2e3e758162ef_1669x348.jpg) 這種頁面中的按鈕權限,是傳統 rbac 很那去控制的。可見此時,用戶有添加 用戶的權限。我們修改一下權限檢測方法 authCheck ~~~ function authCheck($condition=false, $url=''){ $control = lcfirst(request()->controller()); $action = lcfirst(request()->action()); if(empty($condition)){ $checkUrl = $control . '/' . $action; }else{ $checkUrl = $url; if(empty($checkUrl)) return false; // 檢測附加條件 $condition = db('node')->field('condition')->where("rule = '" . $checkUrl . "'")->find(); // 解析附加添加 形如:user|id={uid} and loginnum > 20 if(empty($condition)){ return true; } $rule = explode("|", $condition['condition']); unset($condition); $table = $rule['0']; $where = str_replace("{uid}", session('id'), $rule['1']); $can = db($table)->where($where)->find(); if(empty($can)) return false; } if(!in_array($control, ['login', 'index'])){ if(!in_array($checkUrl, session('action'))){ return false; } } return true; } ~~~ 這樣我們的簡單的 權限檢測 函數就完成了。當然這個函數還很弱,只能檢測某一種規則。如果你想檢測復雜的規則,你可以自己完善和定制更多的規則,原理就是你得會解析這些規則。就像這樣 ~~~ $rule = explode("|", $condition['condition']); unset($condition); $table = $rule['0']; $where = str_replace("{uid}", session('id'), $rule['1']); ~~~ 當然,github上 官方已經寫好了一個類[https://github.com/yunwuxin/think-auth](https://github.com/yunwuxin/think-auth)后面我會講解這個的用法,當然這個就非常強大了,支持很多種認證。 ## 如何去驗證 比如我們去驗證這個需要額外權限的 添加用戶 按鈕是否需要展示,在按鈕頁面 ~~~ <div class="form-group clearfix col-sm-1"> {if(authCheck(true, 'user/useradd'))} <a href="./userAdd"><button class="btn btn-outline btn-primary" type="button">添加用戶</button></a> {/if} </div> 這樣就能驗證,這個添加按鈕的額外權限了。 ## 預告 后面我會研究 官方給的那個擴展,講解一個強大的 auth 權限,本次只是講解自己去實現 auth 的原理。 >
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看