thepublicgood / deadbolt
Deadbolt:为Laravel提供的简单权限管理
Requires
- php: ^7.3|^8.0
- ext-json: *
- laravel/framework: >=7.24
Requires (Dev)
- laravel/legacy-factories: ^1.1
- orchestra/testbench: >=5.0
- phpunit/phpunit: ^8.5|^9.3
- roave/security-advisories: dev-master
README
为什么还需要另一个授权包?
市面上有大量的授权包。但我想找一个比现有的简单得多的包,同时能够容易地与我的包含大量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
这将执行以下两项操作...
- 创建一个名为
add_deadbolt_permissions_column
的新迁移 - 在
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及以上版本。