两个非常棒的 Laravel 权限管理包推荐

file
角色和权限是许多 Web 应用程序的重要组成部分。 有很多为这个部分而写的包,随着 Laravel 历史的发展官方也提供了相关的支持。那么今天这块市场的情况如何?有什么包是最好用的么?这里我有两个推荐。

为什么需要包?

追本遡源 —— Laravel 官方权限功能支持在 5.1.11 版中引入之后就几乎没变过。大概有这些东西:

  • GatesPolicies
  • $this->authorize() 方法
  • @can@cannot Blade 命令

有人可能会说直接用 Laravel 自带的用户授权就足够了,没有必要再用别的软件包了。这是旧包被遗弃的原因之一:自带的功能取代了它们。

但是,在这个领域仍然有这样一些包可以帮助我们实现 Laravel 核心功能不容易实现的权限和角色需求。有两个包做得很好,作者也还在积极维护:

特别提及santigarcor/laratrust,它是已经停止维护的 Entrust 的一个 fork 分支,不然可能会成为强大的第三位选手。 Laratrust 的问题是使用自己的 Laravel 命令替换默认 Laravel 命令,因此无法使用 Gates@can 语法。相反,你需要使用 $user->can(‘edit-user’)@permission Blade 命令。但是如果你不关心这些额外的语法,Laratrust 会是一个很棒的包。它还具有 Spatie 和 Bouncer 的包中没有的团队功能。

还有其它的几个选择,大部分似乎都过时了然后也很久没有被维护了。不过,你可能还是有希望看到他们卷土重来的:

现在,让我们深入了解一下今天两个主角吧。

这些包实际上是做什么的?

他们提供了一个更容易处理角色和权限的 API。此外,最终的代码更容易阅读也更容易理解。

你可以简单使用以下代码来代替分散在不同地方的 PoliciesGates 里创建的权限规则:

$user->givePermissionTo('edit articles'); // Spatie 的包
$user->allow('ban-users'); // Bouncer 的包

基本上,这两个包提供了类似的功能,只是语法和数据库结构略有不同。 接下来进行一个深入的比较。

安装和使用

两个包的安装类似:

  • 添加到 composer 安装;
  • config/app.php 中添加一个提供器和 facade (Bouncer);
  • 发布和运行迁移;
  • 在用户模型中添加一个特殊的 trait ( 这两个包都使用了 Traits);
  • 使用包的方法 ( 有需要的话还能选择性地包含它的类).

这两个包都已经假设你已经有一个默认的 Laravel 用户数据库表,但没有任何角色和权限的结构。 它们会添加自己的表和字段。

这两个包都在 README 上有非常清晰的文档来描述各自的用法。

数据库结构

这是这两个包完全不同的地方。 Spatie 的包有以下表:

file

这里有一些解释:

  • 字段 guard_name 具有默认值 web — 允许你使用多个 guard;
  • 正如你看到的,有两个权限的 中间表 — 角色和用户;
  • 字段 model_type 具有默认值 App\User ,所以没有直接外键关联到 users 表,也没有其他表有 user_id 字段。

现在我们来看看 Bouncer 的数据库:

file

看起来很不一样?Bouncer 的设计的关联更少。让我来解释一下:

  • 权限,Spatie 称之为 permissions, Bouncer 称之为 abilities。 然后,permissions 是附加到 entity 的一组功能;
  • Entity (在所有表中)是分配能力的对象。它可能是角色或用户。因此,与 user_id 或者 users 表没有直接关联,这跟 Spatie 的包一样;
  • 还有一些不同于前者的字段:abilities.titleabilities.only_ownedroles.level。他们添加了一些附加功能,但在 README 文件中并没有很好的解释;
  • Spatie 有 guard 字段但是 Bouncer 没有。

总而言之,Bouncer 的数据库结构似乎更复杂一些,更难于理解,但随之而来的灵活性更大。

可用方法

这两个包确实提供了类似的功能,所以接下来比较一下细节。

创建角色/权限/能力

Spatie

use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;

Role::create(['name' => 'writer']);

Permission::create(['name' => 'edit articles']);

Bouncer

你可以用简短的一句来创建角色和能力:

Bouncer::allow('admin')->to('ban-users');

简单这样写,Bouncer 会在后台为你创建一个 Role 模型和一个 Ability 模型。

你也可以使用 Facade 这样写:

use Silber\Bouncer\Database\Ability;
Ability::create(['name' => 'edit articles']);

正如你所看到的,Bouncer 具有更多的功能,比如自动创建模型。

将角色分配给用户

Spatie

$user->assignRole('writer');
$user->assignRole(['writer', 'admin']);

$user->removeRole('writer');

角色也可以同步:

// 所有当前角色将从用户中删除并替换为给定的数组
$user->syncRoles(['writer', 'admin']);

Bouncer

$user->assign('admin');
$user->assign(['writer', 'admin']);

$user->retract('admin');

非常好的一点是两个包都可以接受单独的角色或数组。

由于 Spatie 的包拥有角色同步 syncRoles 这个功能,在这一部分略胜一筹。这真的是一个很有用的功能,因为如果用 Bouncer 你需要手动执行几个操作。

为用户分配权限/能力

Spatie

$user->givePermissionTo('edit articles');
$user->givePermissionTo('edit articles', 'delete articles');

$user->revokePermissionTo('edit articles');

Bouncer

$user->allow('ban-users');
$user->allow(['ban-users', 'edit-articles']);

你可以将模型名称作为第二个参数传递。

Bouncer::allow($user)->to('edit', Post::class);
Bouncer::allow($user)->to('edit', $post);

$user->disallow('ban-users');
Bouncer::disallow($user)->to('delete', Post::class);

虽然都是类似的功能,但 Bouncer 提供了传递模型类或模型实例的能力。

检查用户的权限/角色

Spatie

检查角色

$user->hasRole('writer');
$user->hasAnyRole(Role::all());
$user->hasAllRoles(Role::all());

检查权限

$user->can('edit articles');
$role->hasPermissionTo('edit articles');

Bouncer

检查角色

$user->isAn('admin');
$user->isA('subscriber', 'editor');
$user->isAll('editor', 'moderator');
$user->isNot('subscriber', 'moderator');

检查权限

Bouncer::allows('edit articles')

这个部分在两个包中都非常相似,不分高下。

Blade 命令

Spatie

@hasanyrole('writer|admin')
    I have one or more of these roles!
@else
    I have none of these roles...
@endhasanyrole

Bouncer

Bouncer 没有添加自己的 Blade 指令。

Spatie 包则增加了几个指令。 当然,这两个包都可以使用默认的 Laravel 命令,如 @can@endcan

高速缓存

Spatie

角色和权限数据被自动缓存以加快性能。

要手动重置这个包的缓存,请运行:

php artisan cache:forget spatie.permission.cache

Bouncer

bouncer 当前请求执行所有查询都会缓存。如果启用了跨请求缓存,缓存会在不同请求之间共享。

无论何时,只要你需要,都可以刷新 bouncer 的缓存:

Bouncer::refresh();

或者,你可以只为特定用户刷新缓存:

Bouncer::refreshFor($user);

在 Bouncer 中缓存有一些更强大的功能。比如启用/禁用缓存,为特定用户刷新缓存也可能会方便。

最终结论

在这里没办法告诉你这两个包哪个更好,因为这两个包都真的很好,这已经上升到了一个偏好的问题。

他们都有自己的一些功能的优势,甚至更多的细节上的设计。

Spatie 的优点:

  • 文档更好 ( Bouncer’s 的一些方法没有在 README 中被提到)
  • 更容易理解的数据库结构
  • syncRoles() 方法可以代替删除插入
  • 一些 blade 命令 —— @role 和 @hasanyrole
  • 支持多个 guard

Bouncer’s 的优点:

  • 更优雅的创建角色和权限
  • 基于模型或实例的权限控制
    • 更好的缓存机制
    • 更强大的数据库结构和一些更有用的字段

如果以上任何一个细节对你来说非常重要,那可能会成就你选择的决定。否则,选择 Spatie 或 Bouncer,都不会让你失望。

附一个额外的礼物

最后,这两个包都提供了一组功能来管理角色和权限,但没有任何 UI 或管理面板进行管理。我准备了一个基于这两个包的 UI 入门工具包。你可以使用它作为样板来管理角色和权限。

以下是 GitHub 上的链接:

参考链接:https://laravel-news.com/two-best-roles-permissions-packages

Stay Hungry, Stay Foolish.