Laravel5权限管理方法详解


Posted in PHP onJuly 26, 2016

本文实例讲述了Laravel5权限管理的实现方法。分享给大家供大家参考,具体如下:

关于权限管理的思考

最近用laravel设计后台,后台需要有个权限管理。权限管理实质上分为两个部分,首先是认证,然后是权限。认证部分非常好做,就是管理员登录,记录session。这个laravel中也有自带Auth来实现这个。最麻烦就是权限认证。

权限认证本质上就是谁有权限管理什么东西。这里有两个方面的维度,谁,就是用户维度,在用户维度,权限管理的粒度可以是用户一个人,也可以是将用户分组,如果将用户分组,则涉及到的逻辑是一个用户可以在多个组里面吗?在另外一方面,管理什么东西,这个东西是物的维度,一个页面是一个东西,一个页面上的一个元素也是一个东西,或者往大了说,一个功能是一个东西。所以做权限管理最重要的是确认这两个维度的粒度。这个已经不是技术的事情了,这个是需要需求讨论的了。

基于上面的思考,我这次想做的权限管理,在用户维度,是基于个人的。就是每个人的权限不一样。在东西的维度,我设置路由为最小的单位,即可以为单个路由设置权限管理。

下面的思考就是使用什么来标记权限,可以使用位,也可以使用字符,也可以使用整型。后来我选择了字符,基于两点考虑:1 字符浅显易懂,在数据库中查找也比较方便 2 我没有按照某个权限查找有这个权限的人的需求,即没有反查需求,使用位,整型等都意义不大。

接下来考虑如何和laravel结合,既然要为每个路由设置访问权限,那么我当然希望能在laravel的route.php路由管理中配置。最好就是在Route::get的时候有个参数能设置permission。这样做的好处是权限设置简易了。在决定路由的时候,就顺手写了权限控制。坏处呢,也很明显,laravel路由的三种方式只能写一种了。就是Route::(method)这样的方式了。

基本决定好了就开干。

路由设计

基本的路由是这样的

Route::post('/admin/validate', ['uses' => 'AdminController@postValidate', 'permissions'=>['admin.validate', 'admin.index']]);

这里在基本的制定路由action之后设置了一个permissions的属性,这个属性设计成数组,因为比如一个post请求,它可能在某个页面会触发,也可能在另外一个页面触发,那么这个post请求就需要同时拥有两个页面路由的权限。

这里使用admin.validate的权限控制,这样,可以将权限分组,admin都是关于admin相关的分组,在数据库中,我就会存储一个二维数组,[admin] => ['validate', 'index']; 存储成二维数组而不是一维的好处呢,一般后台展示是有两个维度的,一个是头部的tab栏,一个是左边的nav栏,就是说这个二维的数组和后台的tab,nav栏是一一对应的。

中间件设计

好了,下面我们就挂上中间件,并且设置所有的路由都走这个中间件

<?php namespace App\Http\Middleware;
use Illuminate\Support\Facades\Session;
use Closure;
class Permission {
  /**
   * Handle an incoming request.
   *
   * @param \Illuminate\Http\Request $request
   * @param \Closure $next
   * @return mixed
   */
  public function handle($request, Closure $next)
  {
    $permits = $this->getPermission($request);
    $admin = \App\Http\Middleware\Authenticate::getAuthUser();
    // 只要有一个有权限,就可以进入这个请求
    foreach ($permits as $permit) {
      if ($permit == '*') {
        return $next($request);
      }
      if ($admin->hasPermission($permit)) {
        return $next($request);
      }
    }
    echo "没有权限,请联系管理员";exit;
  }
  // 获取当前路由需要的权限
  public function getPermission($request)
  {
    $actions = $request->route()->getAction();
    if (empty($actions['permissions'])) {
      echo "路由没有设置权限";exit;
    }
    return $actions['permissions'];
  }
}

这里最关键的就getPermission函数,从$request->route()->getAction()来获取出这个路由的action定义,然后从其中的permissions字段中获取route.php中定义的路由权限。

然后上面的middleware有个:

admin−>hasPermission(admin−>hasPermission(permit);

这个就涉及到model的设计。

model设计

<?php namespace App\Models\Admin;
use App\Models\Model as BaseModel;
class Admin extends BaseModel {
  protected $table = 'admin';
  // 判断是否有某个权限
  public function hasPermission($permission)
  {
    $permission_db = $this->permissions;
    if(in_array($permission, $permission_db)) {
      return true;
    }
    return false;
  }
  // permission 是一个二维数组
  public function getPermissionsAttribute($value)
  {
    if (empty($value)) {
      return [];
    }
    $data = json_decode($value, true);
    $ret = [];
    foreach ($data as $key => $value) {
      $ret[] = $key;
      foreach ($value as $value2) {
        $ret[] = "{$key}.{$value2}";
      }
    }
    return array_unique($ret);
  }
  // 全局设置permission
  public function setPermissionsAttribute($value)
  {
    $ret = [];
    foreach ($value as $item) {
      $keys = explode('.', $item);
      if (count($keys) != 2) {
        continue;
      }
      $ret[$keys[0]][] = $keys[1];
    }
    $this->attributes['permissions'] = json_encode($ret);
  }
}

在数据库中,我将二维数组存储为json,利用laravel的Attribute的get和set方法,完成了数据库中json和外界程序逻辑的连接。然后hasPermission就显得很轻松了,直接判断in_array就ok了。

后续

这个权限认证的逻辑就清晰了。然后如果页面中某个tab或者nav需要对不同权限的用户展示,只需要在view中判断

@if ($admin->hasPermission('admin.index'))
@endif

就可以判断这个用户是否可以看到这个tab了。

总结

这个是一个不算复杂的用户权限实现,但是我感觉已经能满足大部分的后台需求了。当然可以优化的点可能很多,
比如permission是不是可以支持正则,hasPermission如果存储在nosql或者pg中,是不是不用进行json的数据解析,直接一个DB请求就能判断是否有permission之类的?

希望本文所述对大家基于Laravel框架的PHP程序设计有所帮助。

PHP 相关文章推荐
php自动加载机制的深入分析
Jun 08 PHP
详解PHP错误日志的获取方法
Jul 20 PHP
PHP实现操作redis的封装类完整实例
Nov 14 PHP
深入解析PHP中foreach语句控制数组循环的用法
Nov 30 PHP
使用phpstorm和xdebug实现远程调试的方法
Dec 29 PHP
PHP导出Excel实例讲解
Jan 24 PHP
Zend Framework教程之资源(Resources)用法实例详解
Mar 14 PHP
Laravel与CI框架中截取字符串函数
May 08 PHP
PHP在innodb引擎下快速代建全文搜索功能简明教程【基于xunsearch】
Oct 14 PHP
php 判断IP为有效IP地址的方法
Jan 28 PHP
php上传后台无法收到数据解决方法
Oct 28 PHP
Memcached介绍及php-memcache扩展安装
Apr 01 PHP
JavaScript实现删除电脑的关机键
Jul 26 #PHP
php 读取输出其他文件的实现方法
Jul 26 #PHP
php实现贪吃蛇小游戏
Jul 26 #PHP
ThinkPHP和UCenter接口冲突的解决方法
Jul 25 #PHP
php禁用函数设置及查看方法详解
Jul 25 #PHP
Yii2中Restful API原理实例分析
Jul 25 #PHP
Yii2中设置与获取别名的函数(setAlias和getAlias)用法分析
Jul 25 #PHP
You might like
兼容PHP5的PHP目录管理函数库
2008/07/10 PHP
DEDE采集大师官方留后门的删除办法
2011/01/08 PHP
利用PHP生成静态HTML文档的原理
2012/10/29 PHP
ThinkPHP中url隐藏入口文件后接收alipay传值的方法
2014/12/09 PHP
PHP删除指定目录中的所有目录及文件的方法
2015/02/26 PHP
YII Framework框架教程之国际化实现方法
2016/03/14 PHP
smarty的section嵌套循环用法示例
2016/05/28 PHP
PHP session 会话处理函数
2016/06/06 PHP
PHP静态成员变量
2017/02/14 PHP
tp5(thinkPHP5)框架数据库Db增删改查常见操作总结
2019/01/10 PHP
Jquery颜色选择器ColorPicker实现代码
2012/11/14 Javascript
jquery无缝向上滚动实现代码
2013/03/29 Javascript
jQuery实现复选框全选/取消全选/反选及获得选择的值
2014/06/12 Javascript
jQuery中click事件的定义和用法
2014/12/20 Javascript
JavaScript设计模式之外观模式介绍
2014/12/28 Javascript
javascript实现炫酷的拖动分页
2015/05/11 Javascript
微信小程序 教程之条件渲染
2016/10/18 Javascript
ReactJs设置css样式的方法
2017/06/08 Javascript
js数据类型检测总结
2018/08/05 Javascript
IE8中jQuery.load()加载页面不显示的原因
2018/11/15 jQuery
如何使用CSS3和JQuery easing 插件制作绚丽菜单
2019/06/18 jQuery
vue router动态路由设置参数可选问题
2019/08/21 Javascript
浅析vue cli3 封装Svgicon组件正确姿势(推荐)
2020/04/27 Javascript
vue组件系列之TagsInput详解
2020/05/14 Javascript
[03:46]显微镜下的DOTA2第七期——满血与残血
2014/06/20 DOTA
[01:44]《为梦想出发》—联想杯DOTA2完美世界全国高校联赛
2015/09/30 DOTA
python的即时标记项目练习笔记
2014/09/18 Python
Python检测生僻字的实现方法
2016/10/23 Python
详解python 模拟豆瓣登录(豆瓣6.0)
2019/04/18 Python
美国最大的网络男装服装品牌:Bonobos
2017/05/25 全球购物
介绍下Java中==和equals的区别
2013/09/01 面试题
教师专业技术工作总结2015
2015/05/13 职场文书
寻衅滋事罪辩护词
2015/05/21 职场文书
安全教育观后感
2015/06/17 职场文书
《岳阳楼记》原文、译文赏析
2019/09/10 职场文书
golang interface判断为空nil的实现代码
2021/04/24 Golang