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 header示例代码(推荐)
Sep 08 PHP
php数据入库前清理 注意php intval与mysql的int取值范围不同
Dec 12 PHP
PHP开发不能违背的安全规则 过滤用户输入
May 01 PHP
php 获取今日、昨日、上周、本月的起始时间戳和结束时间戳的方法
Sep 28 PHP
phpmyadmin打开很慢的解决方法
Apr 21 PHP
jQuery Mobile + PHP实现文件上传
Dec 12 PHP
PHP二维数组排序简单实现方法
Feb 14 PHP
Yii视图CGridView列表用法实例分析
Jul 12 PHP
基于PHP微信红包的算法探讨
Jul 21 PHP
PHP通过curl获取接口URL的数据方法
May 31 PHP
PHP实现的解汉诺塔问题算法示例
Aug 06 PHP
阿里对象存储OSS在laravel框架中的使用方法
Oct 13 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
php session应用实例 登录验证
2009/03/16 PHP
discuz authcode 经典php加密解密函数解析
2020/07/12 PHP
php 生成文字png图片的代码
2011/04/17 PHP
innerHTML,outerHTML,innerTEXT三者之间的区别
2007/01/28 Javascript
利用div+jquery自定义滚动条样式的2种方法
2013/07/18 Javascript
js子页面获取父页面数据示例
2014/05/15 Javascript
node.js入门教程
2014/06/01 Javascript
JavaScript中的原型prototype属性使用详解
2015/06/05 Javascript
JavaScript的jQuery库插件的简要开发指南
2015/08/12 Javascript
轻松掌握JavaScript享元模式
2016/08/27 Javascript
JS 根据子网掩码,网关计算出所有IP地址范围示例
2020/04/23 Javascript
jquery获取下拉框中的循环值
2017/02/08 Javascript
微信小程序 弹窗自定义实例代码
2017/03/08 Javascript
AngularJS日程表案例详解
2017/08/15 Javascript
Node调用Java的示例代码
2017/09/20 Javascript
vue+vuex+axios+echarts画一个动态更新的中国地图的方法
2017/12/19 Javascript
Spring boot 和Vue开发中CORS跨域问题解决
2018/09/05 Javascript
详解Vue 项目中的几个实用组件(ts)
2019/10/29 Javascript
JavaScript多种图形实现代码实例
2020/06/28 Javascript
深入学习python的yield和generator
2016/03/10 Python
Python正则表达式如何进行字符串替换实例
2016/12/28 Python
python 中的divmod数字处理函数浅析
2017/10/17 Python
Keras在训练期间可视化训练误差和测试误差实例
2020/06/16 Python
基于Tensorflow读取MNIST数据集时网络超时的解决方式
2020/06/22 Python
django restframework serializer 增加自定义字段操作
2020/07/15 Python
利用Python将图片中扭曲矩形的复原
2020/09/07 Python
Zavvi美国:英国娱乐之家
2017/03/19 全球购物
德国街头和运动文化高品质商店:BSTN Store
2017/08/26 全球购物
启动一个线程是用run()还是start()
2016/12/25 面试题
采购部经理岗位职责
2014/02/10 职场文书
庆元旦文艺演出主持词
2014/03/27 职场文书
大学生就业求职信
2014/06/12 职场文书
关心下一代工作先进事迹
2014/08/15 职场文书
小学优秀班主任材料
2014/12/17 职场文书
个人总结与自我评价
2015/02/14 职场文书
电频谱管理的原则是什么
2022/02/18 无线电