高效/权限控制器

AuthorityController 是一个适用于 Laravel 5 的 PHP 授权库,用于限制特定用户可以访问的资源。

2.2.0 2016-05-13 11:29 UTC

README

AuthorityController 是一个适用于 Laravel 5.3 的 PHP 授权库,用于限制特定用户可以访问的资源。

所有权限定义在一个位置

config/authority-controller.php

并在控制器、路由、视图和数据库查询中不会重复。

关于对 Laravel 5.2 的支持,请参阅 AuthorityController 2.2 分支

关于对 Laravel 5.0 或 5.1 的支持,请参阅 AuthorityController 2.1 分支

关于对 Laravel 4.1 或 4.2 的支持,请参阅 AuthorityController 1.2 分支

演示应用程序

您可以通过这个 Laravel 5.3 演示应用程序 看到该包的实际应用。

来源和灵感

这是 authority-laravel 包的一个扩展。

并且是将最佳的 Ruby 授权库 CanCan 端口过来。

Authority 端口了 CanCan 的一些功能,而这个包端口了 几乎所有 其他功能。

安装

使用 Composer

  1. authority-controller 包添加到您的 composer.json 文件中,以要求 AuthorityController
composer require efficiently/authority-controller:dev-master
  1. 将服务提供者添加到 config/app.php
    Efficiently\AuthorityController\AuthorityControllerServiceProvider::class,
  1. 将别名(外观)添加到您的 Laravel 应用配置文件中
    'Params'    => Efficiently\AuthorityController\Facades\Params::class,
    'Authority' => Efficiently\AuthorityController\Facades\Authority::class,
  1. 这将允许您通过您习惯于使用 Laravel 组件的静态接口来访问 Authority 类。
Authority::can('update', SomeModel::class);

配置

创建角色和权限表

我们提供了一种基本的表结构,帮助您开始创建自己的角色和权限。

将它们发布到您的迁移目录或直接复制。

php artisan vendor:publish --provider="Efficiently\AuthorityController\AuthorityControllerServiceProvider" --tag="migrations"

运行迁移

php artisan migrate

这将创建以下表

  • roles
  • role_user
  • permissions

要利用这些表,您可以将以下方法添加到您的 User 模型中。您还需要创建 Role 和 Permission 模型占位符(将 App\Authority\ 替换为您自己的命名空间)。

    //app/User.php
    public function roles()
    {
        return $this->belongsToMany(Authority\Role::class)->withTimestamps();
    }

    public function permissions()
    {
        return $this->hasMany(Authority\Permission::class);
    }

    public function hasRole($key)
    {
        $hasRole = false;
        foreach ($this->roles as $role) {
            if ($role->name === $key) {
                $hasRole = true;
                break;
            }
        }

        return $hasRole;
    }
    //app/Authority/Role.php
    <?php

    namespace App\Authority;

    use Illuminate\Database\Eloquent\Model;

    class Role extends Model {}
    //app/Authority/Permission.php
    <?php

    namespace App\Authority;

    use Illuminate\Database\Eloquent\Model;

    class Permission extends Model {}
初始化资源过滤器和控制器方法

在您的 app/Http/Controllers/Controller.php 文件中,添加 ControllerAdditions 特性并禁用 AuthorizesRequests 特性

<?php

namespace App\Http\Controllers;

use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Efficiently\AuthorityController\ControllerAdditions as AuthorityControllerAdditions;

class Controller extends BaseController
{
    // use AuthorizesRequests;
    use DispatchesJobs, ValidatesRequests;
    use AuthorityControllerAdditions;
    //code...
}

注意:如果您确实需要默认的 Laravel 授权系统,您可以使用 AuthorizesRequests 特性,如果将它的 authorizeauthorizeResource 方法别名化,如下所示

<?php
//code...
class Controller extends BaseController
{
    use DispatchesJobs, ValidatesRequests;
    use AuthorizesRequests, AuthorityControllerAdditions {
        AuthorityControllerAdditions::authorize insteadof AuthorizesRequests;
        AuthorizesRequests::authorize as illuminateAuthorize;
        AuthorizesRequests::authorizeResource as illuminateAuthorizeResource;
    }
    //code...
}

入门

AuthorityController 期望 auth()->user() 返回当前已认证的用户。现在,默认情况下 Laravel 5 处理这个问题

定义权限规则

用户权限在 AuthorityController 的配置文件中定义。

您可以使用以下命令发布 AuthorityController 的默认配置文件

php artisan vendor:publish --provider="Efficiently\AuthorityController\AuthorityControllerServiceProvider" --tag="config"

这将把配置文件的副本放置在 config/authority-controller.php。该配置文件包含一个 initialize 函数,这是设置规则和别名的绝佳位置。

//config/authority-controller.php
<?php

$serializer = new SuperClosure\Serializer;
return [
    'initialize' => $serializer->serialize(function ($authority) {
        $user = auth()->guest() ? new App\User : $authority->getCurrentUser();

        // Action aliases. For example:
        $authority->addAlias('moderate', ['read', 'update', 'delete']);

        // Define abilities for the passed in user here. For example:
        if ($user->hasRole('admin')) {
            $authority->allow('manage', 'all');
        } else {
            $authority->allow('read', 'all');
        }
    })
];

请参阅定义权限规则 获取详细信息。

检查权限规则和授权

然后,您可以使用视图和控制器中的 Authority::can()Authority::cannot() 方法检查当前用户的权限。

@if (Authority::can('update', $article))
    {{ link_to_route("articles.edit", "Edit", $article->id) }}
@endif

请参阅检查权限规则 获取更多信息

如果用户无法执行指定的操作,控制器中的 authorize() 方法将抛出异常。

public function show($id)
{
    $this->article = App\Article::find($id);
    $this->authorize('read', $this->article);
}

为每个操作设置此功能可能会很繁琐,因此提供了 loadAndAuthorizeResource() 方法来自动授权 RESTful 风格资源控制器中的所有操作。它将使用前置过滤器将资源加载到实例变量中并为其每个操作授权。

<?php

namespace App\Http\Controllers;

class ArticlesController extends Controller
{

    public function __construct()
    {
        $this->loadAndAuthorizeResource();
    }

    public function show($id)
    {
        // $this->article is already loaded and authorized
    }
}

请参阅授权控制器操作 获取更多信息。

异常处理

当在控制器中调用 authorize() 并用户无法执行指定的操作时,会抛出 Efficiently\AuthorityController\Exceptions\AccessDenied 异常。可以可选地提供一条消息。

Authority::authorize('read', 'App\Product', 'Unable to read this product.');

您可以在 app/Exceptions/Handler.php 文件的 render() 方法中捕获异常并修改其行为。例如,在这里我们将错误消息设置为闪存并重定向到主页。

//app/Exceptions/Handler.php

   /**
    * Render an exception into an HTTP response.
    *
    * @param  \Illuminate\Http\Request  $request
    * @param  \Exception  $e
    * @return \Illuminate\Http\Response
    */
    public function render($request, Exception $e)
    {
        //code...
        if ($e instanceof \Efficiently\AuthorityController\Exceptions\AccessDenied) {
            $msg = $e->getMessage();
            \Log::error('Access denied! '.$msg);

            return redirect('/home')->with('flash_alert', $msg);
        }

        return parent::render($request, $e);
    }

    //code...

请参阅异常处理 获取更多信息。

文档

Wiki 文档
权限文档

权限 介绍

Authority-Laravel 通用用法

CanCan Wiki 文档

因为 AuthorityController 是 CanCan 的移植版本,您还可以阅读 CanCan 的 Wiki 文档这里

控制器扩展

现在您的控制器具有一个 $params 属性

<?php

namespace App\Http\Controllers;

class ProductsController extends Controller
{
    //code...

    public function update($id)
    {
        $this->params['id'] == $id;//-> true
        $this->params['product'];//-> ["name" => "Best movie"]
        $this->params['controller'];//-> 'products'
        $this->params['action'];//-> 'update'
        //code...
    }

    //code...
}

更新日志

#### 2.3.0-dev

  • 支持 Laravel 5.3!

#### 2.2.0

  • 支持 Laravel 5.2!

#### 2.1.1

  • 更新 Laravel >= 5.1.11 的安装说明

#### 2.1.0

  • 支持 Laravel 5.1!

2.0.1

  • laravelcollective/html 包替换已弃用的包 illuminate/html
  • 自动加载迁移类已无用,请参阅问题 #30(由 @Fnatte 提出)
  • 现在仅在 Composer 的开发模式下自动加载来自 tests 目录的类,以避免冲突

#### 2.0.0

  • 支持 Laravel 5.0!
  • 使用您的 Laravel 别名来解析模型命名空间名称。
  • 或者自动猜测它们,例如 User => App\User
  • 添加一个新的配置选项 controllerClass,默认值为 Illuminate\Routing\Controller
  • 在 Parameters 类中支持路由模型绑定。参见:[https://laravel.net.cn/docs/5.0/routing#route-model-binding](https://laravel.net.cn/docs/5.0/routing#route-model-binding) 和问题 [https://github.com/efficiently/authority-controller/issues/21](https://github.com/efficiently/authority-controller/issues/21)
  • 使用 authority-laravel 包代替 authority-l4
  • 升级说明(如果您之前使用过此包与 Laravel 4)
    • 将您的 authory-controller 配置文件从 app/config/packages/efficiently/authority-controller/config.php 移动到 config/authority-controller.php
    • 发布 authory-controller 迁移文件(参见本 README 中的 创建角色和权限表 部分)

1.2.4

  • 添加 BaseController::flushAuthorityEvents() 静态方法。对于 Codeception 中的功能测试非常有用(参见问题 #14此 Wiki 页面 了解更多信息)。
  • 修复 User::hasRoles() 方法以避免重复角色。

1.2.3

  • 遵循 PSR-2 编码风格

1.2.2

  • 使用 Laravel 4.2 运行测试

1.2.1

  • 修复 composer.json 文件。

1.2.0

  • 安全修复:当存在实际实例对象时,条件回调从未被评估。
  • 不兼容向下:否定规则覆盖先前规则,允许规则不覆盖先前规则,而是进行逻辑或操作(修复 #5)。与 authority-php\authority 包相比,更接近 CanCan 默认行为。有关更多信息,请参阅 Wiki 文档:[https://github.com/efficiently/authority-controller/wiki/Authority-Precedence](https://github.com/efficiently/authority-controller/wiki/Authority-Precedence)
  • 支持 PHP 5.4、5.5、5.6 和 HipHop 虚拟机 (hhvm)。
  • 更新 Parameters 类,允许自定义路由使用 idparent_id 路由参数(修复 #6)。

1.1.3

  • 将 Authority-L4 包升级以修复 Laravel 4.1 支持。

1.1.2

  • 调整模拟系统,该系统模拟 Eloquent 的构造函数方法。

1.1.1

  • 在控制器中减少侵入性的参数注入
    • 检查当前解析的控制器是否响应 paramsBeforeFilter 方法。否则,应用程序会崩溃。
    • 使用当前 Laravel 应用程序的 Controller 别名而不是硬编码的类名。

1.1.0

  • Laravel 4.1 兼容性的第一个 beta 版本。
  • 不兼容 Laravel 4.0

1.0.0

  • 第一个稳定版本,仅兼容 Laravel 4.0
  • 有关 Laravel 4.1 支持,请参阅 [https://github.com/efficiently/authority-controller/tree/1.1](https://github.com/efficiently/authority-controller/tree/1.1) 的 AuthorityController 1.1 分支。
  • 修复 AccessDenied 类,当异常消息为空时,未回退到默认消息。

0.10.0

  • 不兼容向下:Params::get('controller') 的行为现在类似于 Rails。它返回蛇形小写的控制器名称,并以复数形式返回。

0.9.0

  • 第一个 beta 版本

缺少的功能

  1. ControllerResource 类中,使用在 User 模型中使用的 #load_collection 方法。看起来很复杂。相反,使用具有 collectionScope 选项的特定查询作用域,在您的集合(例如 index)控制器操作中过滤您的数据。因为您将通过角色允许/拒绝访问或检查集合中每条记录的用户授权来允许/拒绝访问。
  2. Ability 类中,存在一个 #attributes_for 方法。与 Authority 一起使用时看起来没有用,因为规则条件只能通过 Closure 而不是关联数组来实现。CanCan 只处理 #attribute_forHash(关联数组)条件。
  3. ControllerAdditions 中的 #skip_* 方法。
  4. 对于 Authorityallow()deny() 方法,第三个参数不是一个可选的包含条件的哈希(关联数组),而是一个匿名函数(Closure)。
$authority->allow('update', 'App\Product', function ($self, $product) {
    return $product->available === true;
});

注意事项

兼容性

它**只**与 PHP >= 5.6Laravel >= 5.3 框架兼容。

CanCan 和 AuthorityController 之间的区别

请参阅 Wiki 页面 CanCan 和 AuthorityController 之间的区别

哲学

它遵循 D.R.W.J.P.I. 原则

不要重新发明轮子,只需移植!-- (c) 2013 A.D.

问题或问题?

如果您对 AuthorityController 有任何问题,请添加一个 GitHub 上的 issue 或将该项目进行分支并提交一个 pull request。

要运行测试,您应该安装 PHPUnit 并运行 phpunit tests

特别感谢

AuthorityController 受 CanCan 的强烈启发,并使用 Authority-Laravel