thepublicgood/deadbolt

Deadbolt:为Laravel提供的简单权限管理

v2.2.5 2022-11-29 07:12 UTC

README

Tests

为什么还需要另一个授权包?

市面上有大量的授权包。但我想找一个比现有的简单得多的包,同时能够容易地与我的包含大量JavaScript的现有堆栈一起使用。我已经使用过许多当前顶级的授权包,将来也可能继续使用,但在某些情况下,它们可能有些过于复杂。

Deadbolt非常简单。这从它的名字就可以看出。你可以在配置文件中定义你的权限(这样你就有了一个真实来源),然后你可以将这些权限分配给你的用户。唯一的数据库更改是在你的users表上添加一个permissions列。无需任何额外的迁移或复杂的配置。

Deadbolt的设计就是简单。如果你需要更丰富的功能,还有很多其他选择。如果这个不满足你的需求,那么我的首选包是Spatie的laravel-permission包。

要求

版本3需要PHP 8.1或更高版本以及Laravel 10或更高版本。如果你仍在使用旧版本,则必须坚持使用版本2.2。

安装

Deadbolt可以通过Composer安装

composer require thepublicgood/deadbolt

入门

Deadbolt通过在用户表的列中设置JSON数组中的权限来工作。因此,在您可以使用Deadbolt之前,您需要添加该列。Deadbolt附带了一个简单的Artisan命令,可以为您完成此操作

php ./artisan deadbolt:install

这将执行以下两项操作...

  1. 创建一个名为add_deadbolt_permissions_column的新迁移
  2. config/deadbolt.php中放置Deadbolt配置的副本。

如果您需要,可以修改迁移,但默认情况下会在users表上添加一个名为permissions的列。

现在您可以在deadbolt.php配置文件中定义您的权限。就这样。

deadbolt:install命令仅在config目录中不存在deadbolt.php文件时可用。但是,如果您需要,您始终可以通过运行以下命令来获得相同的结果

php ./artisan vendor:publish --provider=TPG\\Deadbolt\\DeadboltServiceProvider

权限

权限在deadbolt.php配置文件中的$permissions数组中定义,名称任意,例如

$permissions = [
	'Create Articles',
	'Edit Articles',
	'Delete Articles',
];

但是,以这种方式命名权限可能会导致以后的错误。因此,Deadbolt提供了一种创建更简单的权限名称并提供每个权限描述的方法

$permissions = [
	'articles.create' => 'Create Articles',
	'articles.edit' => 'Edit Articles',
	'articles.delete' => 'Delete Articles',
];

在这里定义您的权限的目的是创建一个权限的唯一来源。将一个不存在于此数组的权限分配给用户将引发异常。同样,检查用户是否有不存在的权限也将引发异常。

与权限一起工作

Deadbolt外观

Deadbolt提供了一个名为Deadbolt的Laravel外观。Deadbolt能做的任何事情都可以通过这个外观来处理。

获取定义的权限

您可以轻松获取权限列表

$permissions = Deadbolt::all();

/*
[
	'articles.create',
	'articles.edit',
	'articles.delete',
]
*/

这将返回一个权限名称数组。如果您还想要为每个权限定义的描述,可以使用describe方法

$permissions = Deadbolt::describe();

/*
[
	'articles.create' => 'Create Articles',
	'articles.edit' => 'Edit Articles',
	'articles.delete' => 'Delete Articles',
]
*/

您也可以使用describe方法获取单个权限或一组权限的描述

$permission = Deadbolt::describe('articles.create');
// $permission = 'Create Articles';

$permissions = Deadbolt::describe(['articles.create', 'articles.edit']);

/*
[
	'articles.create' => 'Create Articles',
	'articles.edit' => 'Edit Articles',
]
*/

分配权限

Deadbolt使用“用户”一词来表示任何具有权限并且返回分配权限数组的模型。这可能包括任何具有“权限”属性的Laravel模型,但不一定是实际的User模型。例如,可以是Role模型或Organisation模型。

为了在“用户”上处理权限,Deadbolt在Permissions外观中提供了一个user()方法,您需要传递您的Laravel模型

$deadbolt = Deadbolt::user($request->user());

您可以使用两种主要方法来分配权限。give()方法可用于分配特定权限,而super()方法是一种快速分配所有权限的方式。

// Give a single permission
Deadbolt::user($user)->give('articles.create');

// Give muliple permissions
Deadbolt::user($user)->give('articles.create', 'articles.edit');

// Give an array of permissions
Deadbolt::user($user)->give($arrayOfPermissions);

super()方法实际上只是give(Deadbolt::all())的快捷方式

Deadbolt::user($user)->super();

如果您尝试分配一个不存在的权限,您将得到一个NoSuchPermissionException

Deadbolt::user($user)->give('articles.publish');
// Throws a NoSuchPermissionException.

您可以使用all方法始终获取当前分配给用户的权限数组

$permissions = Deadbolt::user($user)->all();

撤销权限

您可以使用revoke方法从用户那里撤销权限。它与give方法的工作方式非常相似

// Revoke a single permission
Deadbolt::user($user)->revoke('articles.edit');

// Revoke multiple permissions
Deadbolt::user($user)->revoke('articles.edit', 'articles.delete');

// Revoke an array of permissions
Deadbolt::user($user)->revoke($arrayOfArticles);

再次,尝试撤销一个未定义的权限将抛出NoSuchPermissionException,但是如果您尝试撤销一个确实存在但未分配给用户的权限,则revoke方法将不执行任何操作。

此外,还有一个revokeAll方法,它只是移除当前分配给用户的全部权限。

Deadbolt::user($user)->revokeAll();

同步权限

有时同步用户权限非常有用。您可以使用sync方法来完成此操作,它将撤销不在传递数组中的权限,并分配尚未分配的权限

Deadbolt::user($user)->sync($arrayOfPermissions);

本质上,这等同于执行revokeAll()->give($arrayOfPermissions)

测试权限

现在您有了具有权限的用户,您需要能够测试这些权限。Deadbolt为此提供了一套简单的方法。

has

使用has方法来检查用户是否具有所有指定的权限

// Check if a user has a permission
Deadbolt::user($user)->has('articles.create');

// Check that a user has ALL of the permissions
Deadbolt::user($user)->has('articles.create', 'articles.edit');

any

使用any方法来检查用户是否具有任何指定的权限

// Will be true even if only one of the permissions is assigned.
Deadbolt::user($user)->any('articles.edit', 'articles.delete');

none

使用none方法来确保用户不具有任何指定的权限

// Will be false if the user has any of the specified permissions
Deadbolt::user($user)->none('articles.create', 'articles.delete');

多个用户

Deadbolt还允许您同时处理多个用户的权限。通过在Deadbolt外观中使用users方法,您可以通过传递用户模型集合,同时使用同一组方法来处理一个以上的用户。

// Give all the users a permission
Deadbolt::users($users)->give('articles.edit');

// Remove the specified permisssions from all users.
Deadbolt::users($users)->revoke('articles.delete');

对于测试权限,有一组专门用于测试多个用户的特殊方法。

have

使用have方法来测试所有用户都具有指定的权限

// All the users MUST HAVE all of the permissions
Deadbolt::users($users)->have($arrayOfPermissions);

dontHave

使用dontHave方法来确保没有任何用户具有指定的权限

Deadbolt::users($users)->dontHave($arrayOfPermissions);

any

HasPermissions特质

Deadbolt还附带了一个简单的HasPermissions特质,您可以将其添加到您的User模型(或任何赋予权限的模型)中。它通过简单地为您执行Deadbolt::user($user)部分来工作。要开始,只需将HasPermissions特质添加到您的模型中

class User extends Authenticatable
{
    use HasPermissions;

    //...
}

现在您可以通过permissions()方法直接在用户模型上访问Deadbolt

$user = User::find(1);

// Give a permission
$user->permissions()->give('articles.edit');

// Or revoke a permission
$user->permissions()->revoke('articles.edit');

// Or test for a permission
$canEdit = $user->permissions()->has('articles.edit');

HasPermissions特质是可选的,您没有义务使用它而不是直接使用Deadbolt外观。两种方法都是正确的,您可以选择哪种感觉更合适。

Laravel策略

Laravel策略是处理与您不同模型相关联的用户能力的好方法,Deadbolt与Laravel策略配合得非常完美。您可以在此处阅读有关策略的Laravel文档:这里

一个简单的使用Deadbolt的策略可能看起来像这样

<?php

namespace App\\Policies;

use App\\User;
use Illuminate\\Auth\\Access\\HandlesAuthorization;

class ArticlePolicy
{
    use HandlesAuthorization;

    public function create(User $user)
    {
        return Deadbolt::user($user)->has('articles.create');

		// Or if you're using the HasPermissions trait:
		return $user->permissions()->has('articles.create');
    }
}

您可以使用以下方式测试策略

$user->can('create', Article::class);

如果策略需要测试多个权限

public function update(User $user, Article $article)
{
    return Deadbolt::user($user)->hasAll('articles.create', 'articles.edit');

	// Or if you're using the HasPermissions trait:
	return $user->hasAll('articles.create', 'articles.edit');
}

策略可以用来测试如下能力

$user->can('update', $article);

驾驶员

Deadbolt旨在简洁,但有时您可能需要一些更灵活的东西。Deadbolt使用简单的驱动系统来获取权限,因此很容易提供自己的自定义实现。例如,如果您确实想在数据库中存储权限,这将非常有用。

Deadbolt默认包含一个ArrayDriver,该驱动程序从默认的deadbolt.php配置文件中获取权限。如果您想编写自定义驱动程序,可以在调用user()之前通过传递一个新的驱动程序实例给驱动程序方法来实现。

$driver = new DatabaseDriver($config);
Deadbolt::driver($driver))->user($user)->give('...');

每次使用Deadbolt时调用driver方法很烦人,因此您可以在配置文件中设置自定义驱动程序

return [

    'driver' => \App\Drivers\DatabaseDriver::class,

];

自定义驱动程序

例如,如果您需要从数据库中获取权限列表,您可以编写自己的驱动程序。自定义驱动程序类需要实现Drivers\Contacts\DriverInterface,唯一的要求是实现一个permissions方法。

permissions方法必须返回一个权限名称数组

<?php

namespace App\\Drivers;

use Illuminate\\Support\\Arr;
use Illuminate\\Support\\Facades\\DB;
use TPG\\Deadbolt\\Drivers\\Contracts\\DriverInterface;

class DatabaseDriver implements DriverInterface
{
    protected $config;

    public function __construct(array $config)
    {
        $this->config = $config;
    }

    public function permissions(): array
    {
        // return an array of permission names filtered by `$groups`
        // Descriptions MUST be included, or null, even if not set.
        return [
            'articles.create' => 'Create articles',
            'articles.edit' => null,
            'articles.delete' => null,
        ];        
    }
}

permissions方法如何获取权限由您自己决定。它可以是一个数据库请求,甚至是一个远程API请求。

JavaScript辅助工具

Deadbolt包含一个简单的JavaScript辅助工具,提供了一些检查权限的基本工具。您需要将用户权限传递到前端。您可以将Deadbolt类导入到JavaScript组件中。如果您使用Vue,可以这样做

import Deadbolt from '../../vendor/thepublicgood/deadbolt/dist/Deadbolt';

export default {
  props: {
    user: Object,   // The object that has the "permissions" column
  },
  setup (props) {
    
    const permissions = new Deadbolt(props.user.permissions);
    
    // Check if the user has a permission
    permissions.has('articles.create');
    
    // Check if the user has any permission
    permissions.hasAny(['articles.create', 'articles.edit']);
    
    // Check if the user has all permissions
    permissions.hasAll(['articles.edit', 'articles.delete']);
    
    // Check if the user has no permissions
    permissions.hasNone(['articles.edit', 'articles.delete']);
  }
}

从版本1升级

如果您正在将Deadbolt从已经在项目中使用的版本升级,那么您应该能够简单地用Deadbolt 2替换Deadbolt 1。然而,如果您在Deadbolt 1中使用了“组”功能,那么您需要寻找替代方案,因为从Deadbolt 2开始,组不再可用。

此外,如果您正在使用自定义驱动程序,则组的移除将影响方法签名。原始的groups方法已被移除,并且permissions方法不再接受任何参数。

Deadbolt 2仅支持PHP 7.3及以上版本和Laravel 7.0及以上版本。