利用php反射机制 获取权限

来源:互联网 发布:单反入门推荐知乎 编辑:程序博客网 时间:2024/06/05 02:55

之前实现了一个基于角色的权限控制,需要后台手动添加权限,当系统庞大的时候,一条条的加无疑是一场灾难…后来看到公司的权限系统利用php反射机制获取权限,感觉很不错,自己查了下php的反射机制,应用在了自己博客中。 本文代码环境为laravel5.4


一、数据库表结构

截个图吧…

\QQ截图20170804164032.png

pri_name:权限名

pri_desc:权限描述

module_name:模块名

controller:控制器名

action_name:方法名

##二、一些约定

1.代码编写时需要以下的格式

“`php
/**
* @name 添加操作
* @desc 添加操作
* @param Request request@return\Illuminate\Http\JsonResponse/publicfunctionaddOperate(Requestrequest)
{
if(this>user>checkUnique(request->input(‘adminname’))){
return response()->json(msg(‘error’,’该管理员已存在!’));
}
if(this>user>saveUser(request)){
return response()->json(msg(‘success’,’添加成功!’));
}
return response()->json(msg(‘error’,’添加失败!’));
}

“`

需要注释加上@name @desc,@name是必须的

2.还需要配置你需要控制的模块,在config/app.php 加上

/**     * 自定义配置     */    'ACCESS_CHECK_MODULE' => env('ACCESS_CHECK_MODULE','admin'),    'name_space' =>'App\Http\Controllers',

`
.env 文件写上哪些模块需要权限控制

ACCESS_CHECK_MODULE = 'Admin

3.被控制的模块路由地址必须和控制器方法名吻合,比如:

 //角色Route::any('/role/add','RoleController@add');Route::post('/role/addOperate','RoleController@addOperate');Route::get('/role/index','RoleController@index');Route::get('/role/edit/{id}','RoleController@edit')->where('id', '[0-9]+');Route::post('/role/editOperate','RoleController@editOperate');Route::post('/role/delete','RoleController@delete'); ``` ##三、实现PBAC类 这个类的功能只是获取并返回权限 代码如下:```php <?php/** * @name 利用反射获取权限树(路由) * @author [ycp] <[820363773@qq.com]> * Author: ycp * Date: 2017/6/14 * Time: 10:35 * Created by PhpStorm. */namespace App\Models;use ReflectionClass;class Rbac{    public function getAccess(){        //1.获取所有控制器        $modules = config('app.ACCESS_CHECK_MODULE');        $modules = explode(',',$modules);        $controllers =[];        $pris = [];        //获取基础控制器的方法        $base_controller = config('app.name_space').'\\'.'Controller';        $reflection = new ReflectionClass($base_controller);        $action_base_names = $reflection->getMethods();        $action_base_name=[];        foreach ($action_base_names as $v){            $action_base_name[]=$v->name;        }        //循环模块        foreach ($modules as $mk=>$mv){            $controllers = $this->getController($mv);            if($controllers == null){                continue;            }            //循环控制器            foreach ($controllers as $con){                $con_name = str_replace('Controller','',basename($con));                $reflection2 = new ReflectionClass($con);                $action_names = $reflection2->getMethods();                //循环方法                foreach ($action_names as $ak=>$av){                    $av_real = $av->name;                    $desc = $av->getDocComment();                    //控制器名称                    if (!preg_match('/@name\s+(\w+)/u', $desc, $catch)) continue;                    $name = $catch[1];                    //控制器描述                    $description = preg_match('/@desc\s+(\w+)/u', $desc, $catch)                        ? $catch[1]                        : '';                    if(in_array($av_real,$action_base_name) || $av_real == '__construct'){                        continue;                    }else{                        $pris[] = [                            'module_name' =>$mv,                            'controller' =>$con_name,                            'action_name' =>$av_real,                            'pri_name' =>$name,                            'pri_desc' =>$description                        ];                    }                }            }        }        return $pris;    }    /**     * 获取所有控制器名称      * @param string $module     * @return array     */    protected function getController($module){        if(empty($module)){            return null;        }        $module_path = app_path('Http\Controllers').'/'.$module;//模块路径         $module_path = str_replace('\\','/',$module_path);        if(!is_dir($module_path)) {            return null;        };        $module_path .= '/*.php';        $ary_files = glob($module_path);        $files= [];        foreach ($ary_files as $file){            if(is_dir($file) || basename($file,'.php') =='LoginController'){                continue;            }else{                $files[]=config('app.name_space').'\\'.$module.'\\'.basename($file,'.php');            }        }        return $files;    }} ```<div class="se-preview-section-delimiter"></div>##四、添加权限<div class="se-preview-section-delimiter"></div>```php /**     * @name 系统权限添加入库     * @desc 系统权限添加入库     * @return mixed     */    public function refreshPri()    {        $rbac = new Rbac();        $pris = $rbac->getAccess();        $ids = [] ; //更新或者添加的ID        foreach ($pris as $k=>$v){            //添加或者更新已有权限            $pri = $this->updateOrCreate([                'module_name' =>$v['module_name'],                'controller' =>$v['controller'],                'action_name' =>$v['action_name']            ],[                'pri_name' =>$v['pri_name'],                'pri_desc' =>$v['pri_desc']            ]);            $ids[] = $pri->id;        }        //去掉删除的权限        $old_ids = json_decode($this->pluck('id'),true);        $delete_ids = array_diff($old_ids,$ids);        foreach ($delete_ids as $v){            $this->destroy($v);        }        return true;    }

到这里php处理得就差不多了,然后就是前段展示的问题

五、展示权限

截个图…

\QQ截图20170804163830.png

六、权限控制

权限检测都在中间件中进行,定义AdminNeedsPermission中间件

<?phpnamespace App\Http\Middleware;use Closure;class AdminNeedsPermission{    /**     * Handle an incoming request.     *     * @param  \Illuminate\Http\Request  $request     * @param  \Closure  $next     * @return mixed     */    public function handle($request, Closure $next)    {        //公共包不做权限验证        if($request->is('common/*')){            return $next($request);        }       if(checkPri($request->path())){            if(\Request::ajax()){                return response()->json(msg('error','您没有权限访问!'));            }            return redirect('admin')->with(['SYS_INFO'=>'您没有权限访问!']);        }        return $next($request);    }}

checkPri方法:添加到辅助方法helper中

/** * 检测权限 */if ( ! function_exists('checkPri')){    function checkPri($url){        if($url == 'admin'){//首页不验证            return false;        }        $pris = SC::getUserAccess();        if(count($pris)>0){            if(!is_array($url)){                $url = explode('/',$url);            }            foreach ($pris as $pri){                if($pri->admin_id ===1){                    return false;                }                if(strtolower($url[0]) == strtolower($pri->module_name) && strtolower($url[1]) == strtolower($pri->controller) && strtolower($url[2]) == strtolower($pri->action_name)){                    return false;                }            }        }        return true;    }}

总结:实现起来并不复杂,从此不必手动一个个添加权限了

以上代码都在项目https://github.com/ycp19940225/blog可以找到

个人博客:YCP-BLOG

——END

/** * 检测权限 */if ( ! function_exists('checkPri')){    function checkPri($url){        if($url == 'admin'){//首页不验证            return false;        }        $pris = SC::getUserAccess();        if(count($pris)>0){            if(!is_array($url)){                $url = explode('/',$url);            }            foreach ($pris as $pri){                if($pri->admin_id ===1){                    return false;                }                if(strtolower($url[0]) == strtolower($pri->module_name) && strtolower($url[1]) == strtolower($pri->controller) && strtolower($url[2]) == strtolower($pri->action_name)){                    return false;                }            }        }        return true;    }}

总结:实现起来并不复杂,从此不必手动一个个添加权限了

以上代码都在项目https://github.com/ycp19940225/blog可以找到

个人博客:YCP-BLOG

——END