thinkphp5的Auth权限认证实战

thinkphp5的Auth权限认证实战

一、总结

一句话总结:基于角色的权限管理(真正做一遍,就会发现很简单,不然一直都是半懂不懂的

角色 权限

真正做一遍,就会发现很简单,不然一直都是半懂不懂的

 

1、Auth权限认证步骤?

auth 表
界面

a、建立auth表

改auth表名

各个表字段的意思

可以在基础表的基础上增加我们需要的字段

比如排序字段,比如无限级分类的pid字段(比如规则表上面就需要)

 

b、权限界面

用户组管理

规则管理

 

老师端/管理员端(管理端板块布局)

权限管理------

------用户组管理

------规则管理

------------添加规则(上级规则)

 

2、Auth权限类怎么引入系统?

直接 文件夹
composer

直接把Auth.php丢到要用的控制器的那个文件夹中即可

所有的权限认证都可以这么弄的

这样都在同一个文件夹下面,命名空间都是一样的之后,可以直接new 的方式引入类

 

其实也可以用composer的方式弄进来,应该都是直接给你引入好了的

 

3、Auth类的控制应该放到哪里?

基础控制器 初始化方法

获取当前控制器和当前方法的名称(也是Auth类的使用方法)

这个方法还是放到基础控制器的初始化方法里面的

 

 

4、Auth类具体验证是如何进行的?

Auth check 当前 控制器 当前 方法 比较 控制器 方法 数组

获取当前控制器和当前方法的名称(也是Auth类的使用方法)

这个方法还是放到基础控制器的初始化方法里面的

 

 

 

5、权限选择界面如何实现?

tree
上级 下级

选择下级功能的时候默认选择到上级的

所以在获取下级id的时候也是默认需要选择上级的id(其实也不需要,到时候看情况做就好了)

用户组来选择权限,来选择哪些权限为你开放

 

 

6、前端的权限控制如何实现?

不用做
权限数字

前端按钮的隐藏不用做,因为会给你一个没有权限的返回页面,因为权限的控制语句是写在基础控制器的初始化方法里面的

 

如果实现,可以结合后端实现,也可以用权限数字大小来判断

 

7、Beyandadmin简单模板中如何直接从beyand的样式中获取表格?

直接 html

直接获取

把对应的html代码整下来就好了

 

8、做系統,或者做啥子功能,最先,也是最需要的操作是什麼?

设计

做設計,先把界面以及功能設計出來,梳理清楚了,自然也就清楚了。

 

9、Auth权限认证的时候,别改默认的数据表字段?

Auth.php 默认字段

不然Auth类就不好用了,因为Auth.php就是根据默认的字段来写的

如果改了的话,那么Auth类要一起改,其实改起来也很简单

 

10、Auth权限类的使用?

Auth.php 控制器

直接把Auth.php放进控制器,然后注意命名空间,然后调用new类调用方法即可

use app\admin2\controller\Auth;

        $auth=new Auth();
        $group=$auth->getGroups(session('id'));
        dump($group);die;

 

 

11、如何获取当前控制器的当前方法?

Request instance controller action

Request实例的controller和action方法

原生php里面就有方法可以取当前类名和方法名

thinkphp5里面只是对原生方法进行了一点封装而已

1         $request=Request::instance();
2         //當前控制器
3         $con=$request->controller();
4         //當前方法
5         $action=$request->action();
6         $name=$con.'/'.$action;
7         //dump($name);die;

 

 

 

12、Auth权限认证的实质是什么?

当前 控制器 当前 方法 auth_rule 控制字段 对比

拿当前控制器的当前方法和你填写好的Auth_rule里面的控制字段做对比

这是当前控制器的当前方法
string(19) "Authority.admin/add"

那么auth_rule表里面的控制字段也应该是相应的格式

 

 1     //權限驗證
 2     public function doAuthority(){
 3         $auth=new Auth();
 4         $request=Request::instance();
 5         //當前控制器
 6         $con=$request->controller();
 7         //當前方法
 8         $action=$request->action();
 9         $name=$con.'/'.$action;
10         //dump($name);die;
11         if($auth->check($name,session('id'))){
12             $this->error('Failed,No Permission.(失敗,沒有權限)',url('index/index'));
13         }
14     }

 

13、Auth权限认证的核心代码?

new check name

new Auth类,然后调用check方法即可,注意参数name为当前控制器的当前方法

 1     //權限驗證
 2     public function doAuthority(){
 3         $auth=new Auth();
 4         $request=Request::instance();
 5         //當前控制器
 6         $con=$request->controller();
 7         //當前方法
 8         $action=$request->action();
 9         $name=$con.'/'.$action;
10         //dump($name);die;
11         if($auth->check($name,session('id'))){
12             $this->error('Failed,No Permission.(失敗,沒有權限)',url('index/index'));
13         }
14     }

 

 

14、在Auth权限认证中如何给某些特权用户加特权(比如超级管理员不用进行权限认证)?

权限认证 特判

直接在权限认证的位置加特判即可,

所以可以进行各种特判

 1     //權限驗證
 2     public function doAuthority(){
 3         $auth=new Auth();
 4         $request=Request::instance();
 5         //當前控制器
 6         $con=$request->controller();
 7         //當前方法
 8         $action=$request->action();
 9         $name=$con.'/'.$action;
10         //dump($name);die;
11 
12         //超級管理員無需權限驗證
13         $auth_group=$auth->getGroups(session('id'));
14         //dump($auth_group);die;
15         if(isset($auth_group[0]['aga_ag_id'])&&$auth_group[0]['aga_ag_id']==3){
16 
17         }else{
18             if(!$auth->check($name,session('id'))){
19                 $this->error('Failed,No Permission.',url('index/index'));
20             }
21         }
22         //
23 
24     }

 

15、如何指定某些页面不进行权限认证?

数组 页面 特判

用数组将不进行权限认证的页面弄出来,然后进行特判即可

页面可以用控制器/方法来表示

16         //某些頁面不進行權限認證
17         $notCheck=array('Index/index');
 1     //權限驗證
 2     public function doAuthority(){
 3         $auth=new Auth();
 4         $request=Request::instance();
 5         //當前控制器
 6         $con=$request->controller();
 7         //當前方法
 8         $action=$request->action();
 9         $name=$con.'/'.$action;
10         //dump($name);die;
11 
12         //超級管理員無需權限驗證
13         $auth_group=$auth->getGroups(session('id'));
14         //dump($auth_group);die;
15 
16         //某些頁面不進行權限認證
17         $notCheck=array('Index/index');
18         if(isset($auth_group[0]['aga_ag_id'])&&$auth_group[0]['aga_ag_id']==3){
19 
20         }else{
21             if(!in_array($name,$notCheck)){
22                 if(!$auth->check($name,session('id'))){
23                     $this->error('Failed,No Permission.',url('index/index'));
24                 }
25             }
26         }
27         //
28 
29     }

 

16、Auth权限认证整个流程实质?

控制器/方法 数组 比较 当前 控制器 当前 方法

给用户分到权限组

给权限组指定规则

规则可以"控制器/方法名"的方式表示

然后那用户对应的权限组的"控制器/方法名"的数组和当前控制器/当前方法做比较,符合条件则让进入页面,否则不让

 

17、Auth权限是后端的权限,前端的权限怎么解决?

js 类 统一控制

加上类,直接js实现,简单方便,而且方便开发

分为三类:

管理员端的东西:比如跨班级的东西

老师端的东西:比如提交系统反馈啊

本人的东西:比如资源的修改删除,

加js类做统一控制

比如资源的修改删除,是管理员也可以,然后老师本人也可以,但是本班的别的老师不行

 

 

二、Auth权限认证核心代码

1、验证的代码

这里注意auth类的引入

use app\admin2\controller\Auth;

验证是在基础控制器的初始化方法中

class Base extends Controller
{
    //任何一个方法执行都会调用这个方法
    public function _initialize()
    {
        $this->doAuthority();
    }

 

 1     //權限驗證
 2     public function doAuthority(){
 3         $auth=new Auth();
 4         $request=Request::instance();
 5         //當前控制器
 6         $con=$request->controller();
 7         //當前方法
 8         $action=$request->action();
 9         $name=$con.'/'.$action;
10         //dump($name);die;
11 
12         //超級管理員無需權限驗證
13         $auth_group=$auth->getGroups(session('id'));
14         //dump($auth_group);die;
15 
16         //某些頁面不進行權限認證
17         $notCheck=array('Index/index');
18         if(isset($auth_group[0]['aga_ag_id'])&&$auth_group[0]['aga_ag_id']==3){
19 
20         }else{
21             if(!in_array($name,$notCheck)){
22                 if(!$auth->check($name,session('id'))){
23                     $this->error('Failed,No Permission.',url('index/index'));
24                 }
25             }
26         }
27         //
28 
29     }

 

2、验证类及数据表

数据表最好不要动,如果动了的话,记得改下面方法里面的字段

  1 <?php
  2 // +----------------------------------------------------------------------
  3 // | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
  4 // +----------------------------------------------------------------------
  5 // | Copyright (c) 2011 http://thinkphp.cn All rights reserved.
  6 // +----------------------------------------------------------------------
  7 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8 // +----------------------------------------------------------------------
  9 // | Author: luofei614 <weibo.com/luofei614> 
 10 // +----------------------------------------------------------------------
 11 namespace app\admin\controller;
 12 use think\Config;
 13 use think\Session;
 14 use think\Db;
 15 /**
 16  * 权限认证类
 17  * 功能特性:
 18  * 1,是对规则进行认证,不是对节点进行认证。用户可以把节点当作规则名称实现对节点进行认证。
 19  *      $auth=new Auth();  $auth->check('规则名称','用户id')
 20  * 2,可以同时对多条规则进行认证,并设置多条规则的关系(or或者and)
 21  *      $auth=new Auth();  $auth->check('规则1,规则2','用户id','and') 
 22  *      第三个参数为and时表示,用户需要同时具有规则1和规则2的权限。 当第三个参数为or时,表示用户值需要具备其中一个条件即可。默认为or
 23  * 3,一个用户可以属于多个用户组(think_auth_group_access表 定义了用户所属用户组)。我们需要设置每个用户组拥有哪些规则(think_auth_group 定义了用户组权限)
 24  * 
 25  * 4,支持规则表达式。
 26  *      在think_auth_rule 表中定义一条规则时,如果type为1, condition字段就可以定义规则表达式。 如定义{score}>5  and {score}<100  表示用户的分数在5-100之间时这条规则才会通过。
 27  */
 28 //数据库
 29 /*
 30   -- ----------------------------
 31   -- bk_auth_rule,规则表,
 32   -- id:主键,name:规则唯一标识, title:规则中文名称 status 状态:为1正常,为0禁用,condition:规则表达式,为空表示存在就验证,不为空表示按照条件验证
 33   -- ----------------------------
 34   DROP TABLE IF EXISTS `bk_auth_rule`;
 35   CREATE TABLE `bk_auth_rule` (
 36   `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
 37   `name` char(80) NOT NULL DEFAULT '',
 38   `title` char(20) NOT NULL DEFAULT '',
 39   `type` tinyint(1) NOT NULL DEFAULT '1',
 40   `status` tinyint(1) NOT NULL DEFAULT '1',
 41   `condition` char(100) NOT NULL DEFAULT '',  # 规则附件条件,满足附加条件的规则,才认为是有效的规则
 42   PRIMARY KEY (`id`),
 43   UNIQUE KEY `name` (`name`)
 44   ) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
 45   -- ----------------------------
 46   -- bk_auth_group 用户组表,
 47   -- id:主键, title:用户组中文名称, rules:用户组拥有的规则id, 多个规则","隔开,status 状态:为1正常,为0禁用
 48   -- ----------------------------
 49   DROP TABLE IF EXISTS `bk_auth_group`;
 50   CREATE TABLE `bk_auth_group` (
 51   `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
 52   `title` char(100) NOT NULL DEFAULT '',
 53   `status` tinyint(1) NOT NULL DEFAULT '1',
 54   `rules` char(80) NOT NULL DEFAULT '',
 55   PRIMARY KEY (`id`)
 56   ) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
 57   -- ----------------------------
 58   -- bk_auth_group_access 用户组明细表
 59   -- uid:用户id,group_id:用户组id
 60   -- ----------------------------
 61   DROP TABLE IF EXISTS `bk_auth_group_access`;
 62   CREATE TABLE `bk_auth_group_access` (
 63   `uid` mediumint(8) unsigned NOT NULL,
 64   `group_id` mediumint(8) unsigned NOT NULL,
 65   UNIQUE KEY `uid_group_id` (`uid`,`group_id`),
 66   KEY `uid` (`uid`),
 67   KEY `group_id` (`group_id`)
 68   ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
 69  */
 70 
 71 class Auth {
 72     //默认配置
 73     protected $config = array(
 74         'auth_on'           => true,                      // 认证开关
 75         'auth_type'         => 2,                         // 认证方式,1为实时认证;2为登录认证。
 76         'auth_group'        => 'auth_group',        // 用户组数据表名
 77         'auth_group_access' => 'auth_group_access', // 用户-用户组关系表
 78         'auth_rule'         => 'auth_rule',         // 权限规则表
 79         'auth_user'         => 'auth_member'             // 用户信息表
 80     );
 81     
 82     public function __construct() {
 83         if (Config::get('auth_config')) {
 84             $this->config = array_merge($this->config, Config::get('auth_config')); //可设置配置项 auth_config, 此配置项为数组。
 85         }
 86     }
 87     /**
 88      * 检查权限
 89      * @param name string|array  需要验证的规则列表,支持逗号分隔的权限规则或索引数组
 90      * @param uid  int           认证用户的id
 91      * @param string mode        执行check的模式
 92      * @param relation string    如果为 'or' 表示满足任一条规则即通过验证;如果为 'and'则表示需满足所有规则才能通过验证
 93      * return boolean           通过验证返回true;失败返回false
 94      */
 95     public function check($name, $uid, $type = 1, $mode = 'url', $relation = 'or') {
 96         if (!$this->config['auth_on']) {
 97             return true;
 98         }
 99         $authList = $this->getAuthList($uid, $type); //获取用户需要验证的所有有效规则列表
100         if (is_string($name)) {
101             $name = strtolower($name);
102 //            if (strpos($name, ',') !== false) {
103 //                $name = explode(',', $name);
104 //            } else {
105 //                $name = [$name];
106 //            }
107             $name = strpos($name, ',') !== false ? explode(',', $name) : [$name];
108         }
109         $list = []; //保存验证通过的规则名
110         if ($mode == 'url') {
111             $REQUEST = unserialize(strtolower(serialize($_REQUEST)));
112         }
113         foreach ($authList as $auth) {
114             $query = preg_replace('/^.+\?/U', '', $auth);
115             if ($mode == 'url' && $query != $auth) {
116                 parse_str($query, $param); //解析规则中的param
117                 $intersect = array_intersect_assoc($REQUEST, $param);
118                 $auth = preg_replace('/\?.*$/U', '', $auth);
119                 if (in_array($auth, $name) && $intersect == $param) {  //如果节点相符且url参数满足
120                     $list[] = $auth;
121                 }
122             } else if (in_array($auth, $name)) {
123                 $list[] = $auth;
124             }
125         }
126         if ($relation == 'or' and ! empty($list)) {
127             return true;
128         }
129         $diff = array_diff($name, $list);
130         if ($relation == 'and' and empty($diff)) {
131             return true;
132         }
133         return false;
134     }
135     /**
136      * 根据用户id获取用户组,返回值为数组
137      * @param  uid int     用户id
138      * return array       用户所属的用户组 [
139      *     ['uid'=>'用户id','group_id'=>'用户组id','title'=>'用户组名称','rules'=>'用户组拥有的规则id,多个,号隔开'),
140      *     ...)   
141      */
142     public function getGroups($uid) {
143         static $groups = [];
144         if (isset($groups[$uid])) {
145             return $groups[$uid];
146         }
147         $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")
148                         ->where(['uid' => $uid, 'status' => 1])->select();
149         $groups[$uid] = $user_groups ? $user_groups : [];
150         return $groups[$uid];
151     }
152     /**
153      * 获得权限列表
154      * @param integer $uid  用户id
155      * @param integer $type 
156      */
157     protected function getAuthList($uid, $type) {
158         static $_authList = []; //保存用户验证通过的权限列表
159         $t = implode(',', (array) $type);
160         if (isset($_authList[$uid . $t])) {
161             return $_authList[$uid . $t];
162         }
163         if ($this->config['auth_type'] == 2 && Session::has('_auth_list_' . $uid . $t)) {
164             return Session::get('_auth_list_' . $uid . $t);
165         }
166         //读取用户所属用户组
167         $groups = $this->getGroups($uid);
168         $ids = []; //保存用户所属用户组设置的所有权限规则id
169         foreach ($groups as $g) {
170             $ids = array_merge($ids, explode(',', trim($g['rules'], ',')));
171         }
172         $ids = array_unique($ids);
173         if (empty($ids)) {
174             $_authList[$uid . $t] = [];
175             return [];
176         }
177         $map = [
178             'id' => ['in', $ids],
179             'type' => $type,
180             'status' => 1,
181         ];
182         //读取用户组所有权限规则
183         $rules = Db::name($this->config['auth_rule'])->where($map)->field('condition,name')->select();
184         //循环规则,判断结果。
185         $authList = [];   //
186         foreach ($rules as $rule) {
187             if (!empty($rule['condition'])) { //根据condition进行验证
188                 $this->getUserInfo($uid); //获取用户信息,一维数组
189                 $command = preg_replace('/\{(\w*?)\}/', '$user[\'\\1\']', $rule['condition']);
190                 @(eval('$condition=(' . $command . ');'));
191                 $condition && $authList[] = strtolower($rule['name']);
192             } else {
193                 $authList[] = strtolower($rule['name']); //只要存在就记录
194             }
195         }
196         $_authList[$uid . $t] = $authList;
197         if ($this->config['auth_type'] == 2) {
198             $_SESSION['_auth_list_' . $uid . $t] = $authList; //规则列表结果保存到session
199         }
200         return array_unique($authList);
201     }
202     /**
203      * 获得用户资料,根据自己的情况读取数据库
204      */
205     protected function getUserInfo($uid) {
206         static $userinfo = [];
207         if (!isset($userinfo[$uid])) {
208             $userinfo[$uid] = Db::name($this->config['auth_user'])->where(['uid' => $uid])->find();
209         }
210         return $userinfo[$uid];
211     }
212 }

 

 

 

 

 
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值