利用php反射机制 获取权限

之前实现了一个基于角色的权限控制,需要后台手动添加权限,当系统庞大的时候,一条条的加无疑是一场灾难…后来看到公司的权限系统利用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(Request request)
{
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中间件

<?php

namespace 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

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值