之前实现了一个基于角色的权限控制,需要后台手动添加权限,当系统庞大的时候,一条条的加无疑是一场灾难…后来看到公司的权限系统利用php反射机制获取权限,感觉很不错,自己查了下php的反射机制,应用在了自己博客中。 本文代码环境为laravel5.4
截个图吧…
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
/**
* @name 利用反射获取权限树(路由)
* @author [ycp] <[[email protected]]>
* 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;
}
}
```
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处理得就差不多了,然后就是前段展示的问题
五、展示权限
截个图…
六、权限控制
权限检测都在中间件中进行,定义AdminNeedsPermission中间件
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