genealabs/laravel-governor

管理Laravel中的策略和控制。

0.20.1 2024-05-13 23:32 UTC

README

Build Status Coverage Status Latest StableVersion Total Downloads

Governor for Laravel

在您的Laravel应用程序中通过细粒度的基于角色的权限管理授权。

screencast 2017-06-04 at 3 34 56 pm

目标

提供一种简单的方法来管理基于Laravel授权功能的Laravel应用程序中的ACL。通过利用Laravel的本地授权功能,无需额外的学习或实现曲线。您只需要了解Laravel,就会知道如何使用Laravel的Governor。

要求

  • PHP >=7.1.3
  • Laravel >= 5.5
  • Bootstrap 3(需要包含在您的布局文件中)
  • FontAwesome 4(需要包含在您的布局文件中)

安装

具有最低主键的用户将被设置为超级管理员。如果您正在开始一个新项目,请确保现在添加一个初始用户。如果您已经有了用户,您可以将角色-用户条目更新为指向您想要的用户,如果第一个用户不是预期的超级管理员。现在让我们安装这个包。

通过Composer安装

composer require genealabs/laravel-governor

实现

  1. 首先,我们需要通过运行迁移和数据种子来更新数据库

    php artisan migrate --path="vendor/genealabs/laravel-governor/database/migrations"
    php artisan db:seed --class=LaravelGovernorDatabaseSeeder
  2. 如果您有自己的种子,现在运行它们

    php artisan db:seed
  3. 接下来,分配权限(这需要您已经填充了用户)

    php artisan db:seed --class=LaravelGovernorPermissionsTableSeeder
  4. 现在我们需要使资源可用

    php artisan governor:publish --assets
  5. 最后,将可管理的特性添加到您的应用程序的用户模型中

    // [...]
    use GeneaLabs\LaravelGovernor\Traits\Governable;
    
    class User extends Authenticatable
    {
        use Governable;
        // [...]
    }

升级

以下升级指南可以帮助您导航有破坏性变更的更新。

从0.11.5+到0.12 [破坏性]

由于Laravel不完全支持复合键,角色_user 连接表已用主键替换了复合键。运行

php artisan db:seed --class="LaravelGovernorUpgradeTo0120"

从0.11到0.11.5 [破坏性]

包的表的主键已被重命名。(这应该是一个小版本更改,而不是补丁,因为这个是一个破坏性更改。)运行

php artisan db:seed --class="LaravelGovernorUpgradeTo0115"

从0.10到0.11 [破坏性]

以下特性已更改

  • Governable 已重命名为 Governing
  • Governed 已重命名为 Governable
  • governor_created_by 重命名为 governor_owned_by。运行迁移以更新您的表。
    php artisan db:seed --class="LaravelGovernorUpgradeTo0110"
  • 在您的应用程序中替换任何对 governor_created_by 的引用为 governor_owned_by

从0.6到版本0.10 [破坏性]

要从0.10.0之前的版本升级,首先运行迁移和种子,然后运行更新种子

php artisan migrate --path="vendor/genealabs/laravel-governor/database/migrations"
php artisan db:seed --class="LaravelGovernorDatabaseSeeder"
php artisan db:seed --class="LaravelGovernorUpgradeTo0100"

到0.6 [破坏性]

  1. 如果您正在扩展 GeneaLabs\LaravelGovernor\Policies\LaravelGovernorPolicy,则更改为扩展 GeneaLabs\LaravelGovernor\Policies\BasePolicy
  2. 已删除对低于5.5版本的Laravel的支持。

配置

如果您需要更改默认配置(请参阅下面的示例选择默认配置文件),请发布配置文件

php artisan governor:publish --config

并进行任何必要的更改。(我们不推荐在没有更改的情况下发布配置文件。)

视图

如果您想自定义视图,请发布它们

php artisan governor:publish --views

并在 resources\views\vendor\genealabs\laravel-governor 中编辑它们。

策略

策略现在可以自动检测并自动添加到实体列表中。您将不再需要手动管理实体。在编辑角色时,新策略将可用于角色分配。请查看下面的示例策略。有关如何在代码中创建策略和检查策略的文档,请参阅Laravel的官方文档:https://laravel.net.cn/docs/5.4/authorization#writing-policies

您的策略必须扩展LaravelGovernorPolicy才能与Governor一起使用。 默认情况下,您不需要包含任何方法,因为它们会自动实现并基于反射进行检查。但是,如果您需要自定义任何内容,您可以自由重写任何beforecreateeditviewinspectremove方法。

检查授权

要验证用户是否满足给定策略,请使用Governor验证的关键词之一:beforecreateeditviewinspectremove。例如,如果需要检查的策略类名为BlogPostPolicy,您可以使用$user->can('create', (new BlogPost))$user->can('edit', $blogPost)来授权您的用户。

过滤查询以显示允许的自身项目

通常希望用户只能看到他们有权访问的项目。这以前很难且很繁琐。以Nova为例,您现在可以按以下方式限制索引视图:```php <?php namespace App\Nova;

use Laravel\Nova\Resource as NovaResource;
use Laravel\Nova\Http\Requests\NovaRequest;

abstract class Resource extends NovaResource
{
    public static function indexQuery(NovaRequest $request, $query)
    {
        $model = $query->getModel();

        if ($model
            && is_object($model)
            && method_exists($model, "filterViewAnyable")
        ) {
            $query = $model->filterViewAnyable($query);
        }

        return $query;
    }

    // ...
}
```

The available query filters are:
- `filterDeletable(Builder $query)`
- `filterUpdatable(Builder $query)`
- `filterViewable(Builder $query)`
- `filterViewAnyable(Builder $query)`

The same functionality is availabe via model scopes, as well:
- `deletable()`
- `updatable()`
- `viewable()`
- `viewAnyable()`

表格

表格将自动更新为带有governor_owned_by列的列,该列引用创建条目的用户。不再需要运行单独的迁移或解决没有created_by属性的模型的问题。

管理视图

将Governor集成到您的Laravel应用程序中的最简单方法是在应用程序菜单的相关部分添加菜单项(请确保使用Laravel授权方法适当限制访问)。以下路由可以添加

  • 角色管理:genealabs.laravel-governor.roles.index
  • 用户-角色分配:genealabs.laravel-governor.assignments.index

例如

<li><a href="{{ route('genealabs.laravel-governor.roles.index') }}">Governor</a></li>

403未授权

我们建议创建自定义403错误页面,以便用户知道他们没有访问权限。否则,用户将只能看到默认的错误消息。有关如何设置这些页面的更多详细信息,请参阅https://laravel.net.cn/docs/5.4/errors#custom-http-error-pages

授权API

您可以通过公共API检查用户执行某些操作的能力。建议使用Laravel Passport在您的客户端和后端之间维护会话状态。以下是一个检查当前登录用户是否有权创建GeneaLabs\LaravelGovernor\Role模型记录的示例

$response = $this
    ->json(
        "GET",
        route('genealabs.laravel-governor.api.user-can.show', "create"),
        [
            "model" => "GeneaLabs\LaravelGovernor\Role",
        ]
    );

以下示例检查用户是否有权编辑GeneaLabs\LaravelGovernor\Role模型记录

$response = $this
    ->json(
        "GET",
        route('genealabs.laravel-governor.api.user-can.show', "edit"),
        [
            "model" => "GeneaLabs\LaravelGovernor\Role",
            "primary-key" => 1,
        ]
    );

除了createview之外,inspecteditremove能力都需要传递主键。

角色检查API

// TODO: 添加文档

$response = $this
    ->json(
        "GET",
        route('genealabs.laravel-governor.api.user-is.show', "SuperAdmin")
    );

示例

配置文件

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Layout Blade File
    |--------------------------------------------------------------------------
    |
    | This value is used to reference your main layout blade view to render
    | the views provided by this package. The layout view referenced here
    | should include Bootstrap 3 and FontAwesome 4 to work as intended.
    */
    'layout-view' => 'layouts.app',

    /*
    |--------------------------------------------------------------------------
    | Layout Content Section Name
    |--------------------------------------------------------------------------
    |
    | Specify the name of the section in the view referenced above that is
    | used to render the main page content. If this does not match, you
    | will only get blank pages when accessing views in Governor.
    */
    'content-section' => 'content',

    /*
    |--------------------------------------------------------------------------
    | Authorization Model
    |--------------------------------------------------------------------------
    |
    | Here you can customize what model should be used for authorization checks
    | in the event that you have customized your authentication processes.
    */
    'auth-model' => config('auth.providers.users.model') ?? config('auth.model'),

    /*
    |--------------------------------------------------------------------------
    | User Model Name Property
    |--------------------------------------------------------------------------
    |
    | This value is used to display your users when assigning them to roles.
    | You can choose any property of your auth-model defined above that is
    | exposed via JSON.
    */
    'user-name-property' => 'name',

    /*
    |--------------------------------------------------------------------------
    | URL Prefix
    |--------------------------------------------------------------------------
    |
    | If you want to change the URL used by the browser to access the admin
    | pages, you can do so here. Be careful to avoid collisions with any
    | existing URLs of your app when doing so.
    */
    'url-prefix' => '/genealabs/laravel-governor/',
];

策略

默认策略无需方法

添加策略非常简单!所有的工作都已重构,因此您现在只需创建一个策略类即可,就这么简单!

<?php namespace GeneaLabs\LaravelGovernor\Policies;

use GeneaLabs\LaravelGovernor\Interfaces\GovernablePolicy;
use Illuminate\Auth\Access\HandlesAuthorization;

class MyPolicy extends LaravelGovernorPolicy
{
    use HandlesAuthorization;
}

策略类中的默认方法

如果您想自定义特定方法,则只需将任何beforecreateupdateviewviewAnydeleterestoreforceDelete方法添加到策略中即可。

abstract class BasePolicy
{
    public function before($user)
    {
        return $user->hasRole("SuperAdmin")
            ?: null;
    }

    public function create(Model $user) : bool
    {
        return $this->validatePermissions(
            $user,
            'create',
            $this->entity
        );
    }

    public function update(Model $user, Model $model) : bool
    {
        return $this->validatePermissions(
            $user,
            'update',
            $this->entity,
            $model->governor_owned_by
        );
    }

    public function viewAny(Model $user) : bool
    {
        return true;

        return $this->validatePermissions(
            $user,
            'viewAny',
            $this->entity
        );
    }

    public function view(Model $user, Model $model) : bool
    {
        return $this->validatePermissions(
            $user,
            'view',
            $this->entity,
            $model->governor_owned_by
        );
    }

    public function delete(Model $user, Model $model) : bool
    {
        return $this->validatePermissions(
            $user,
            'delete',
            $this->entity,
            $model->governor_owned_by
        );
    }

    public function restore(Model $user, Model $model) : bool
    {
        return $this->validatePermissions(
            $user,
            'restore',
            $this->entity,
            $model->governor_owned_by
        );
    }

    public function forceDelete(Model $user, Model $model) : bool
    {
        return $this->validatePermissions(
            $user,
            'forceDelete',
            $this->entity,
            $model->governor_owned_by
        );
    }
}