[扩展包] JosephSilber/bouncer 的使用
在社区中没找到 JosephSilber/bouncer 的翻译。自己瞎翻译了一下。才疏学浅,用了整整一下午才翻译完。可能有很多翻译的不好的地方,还望各位大佬指正。里面有部分内容原文是在不同地方的,我把他们放一起了,方便查看。如:缓存。
原文地址:https://github.com/JosephSilber/bouncer#al...
Bouncer 是一个优雅的,与框架无关的扩展包,它可以使用 Eloquent 模型管理任何应用程序的角色和权限。
它使用富有表现力和流畅的语法,对它你可以呼之则来,挥之则去。
安装
通过 composer 来安装:
$ composer require silber/bouncer v1.0.0-rc.1
安装完成后,可以通过以下步骤来使用( laravel 5.5 以上版本服务提供者和别名会自动注册,可以跳过1,2步):
-
在
provider
数组中添加一个新的元素:Silber\Bouncer\BouncerServiceProvider::class,
-
向
aliases
数组中添加新元素:'Bouncer'=>Silber\Bouncer\BouncerFacade::class,
-
向用户模型中添加 Bouncer 的 Trait
use Silber\Bouncer\Database\HasRolesAndAbilities;
class User extends Model
{
use HasRolesAndAbilities;
}
-
执行 Bouncer 的数据迁移,通过以下命令,将迁移发布到你的
migrations
目录中。php artisan vendor:publish --tag="bouncer.migrations"
-
最后执行数据迁移
php artisan migrate
Facade(门面)
使用 Bouncer 门面时,你需要在文件顶部的命名空间处添加一行:use Bouncer;
如果想了解更多 Laravel Facade 的相关信息,可以去 Laravel 文档 了解;
启用缓存
默认情况,Bouncer 的查询请求将会被缓存,为了获得更好的性能,你可能会使用到 跨请求
缓存。
Bouncer::cache();
当你启用了 跨请求
缓存时,你需要在每次更改角色/能力时都刷新缓存;
Bouncer :: refresh();
完全刷新所有用户的缓存时,将使用 缓存标记
(如果你的驱动支持的话,参阅 Laravel 文档 确认你的驱动是否支持缓存标记),并非所有驱动都支持缓存标记,对于不支持缓存标记的用户,调用 fresh
方法可能会比较慢,具体取决于用户数量;
当然,你也可以为特定用户刷新缓存:
Bouncer::refreshFor($user);
禁用缓存
当你想禁用缓存时,可以使用:
Bouncer::dontCache();
当你在单元测试中,想针对刚被授权的用户/能力进行断言时非常有用;
用法
向用户添加角色和权限将变得非常容易。你无需事先创建一个角色或者权限。只需要传递角色/权限的名称,如果名称不存在,Bouncer 将会自动创建;
创建一个角色并使他可以在网站中禁用用户:
Bouncer::allow('admin')->to('ban-users');
在幕后,Bouncer 将会帮你创建一个 Role 模型和 Ability 模型。
如果你想为角色/能力添加更多属性,例如人类可读的标题,你可以使用 BOuncer 下面的 Role 和 Ability 方法创建它们。
$admin = Bouncer::role()->firstOrCreate([
'name' => 'admin',
'title' => 'Administrator',
]);
$ban = Bouncer::ability()->firstOrCreate([
'name' => 'ban-users',
'title' => 'Ban users',
]);
Bouncer::allow($admin)->to($ban);
为用户分配角色
为用户赋予一个 admin 的角色:
Bouncer::assign('admin')->to($user);
也可以用用户模型调用 assign 方法赋予:
$user->assign('admin');
为用户分配某个权限
有时候,你需要绕开角色,直接给用户赋予某个权限:
Bouncer::allow($user)->to('ban-users');
同样,你还可以直接使用用户模型调用 allow 方法:
$user->allow('ban-users');
限制模型能力
当你想限制某个特定模型类型的权限时,可以将模型名字作为第二个参数传入:
Bouncer::allow($user)->to('edit', Post::class);
如果要限制特定模型实例的权限,则将实例化模型作为第二参数传入:
Bouncer::allow($user)->to('edit', $post);
允许用户或者角色 “拥有” 一个模型
可以使用 toOwn 方法允许用户管理它们自己的模型:
Bouncer::allow($user)->toOwn(Post::class);
现在,当在 gate 中检查用户是否可以在给定的帖子中执行某个动作时,帖子的 user_id 将会和已登录用户的 id 进行比较。如果匹配,gate 将会允许这个动作。
用户将会被赋予“拥有的”模型所有权限。你可以调用 to
方法来限制他的权限。
Bouncer::allow($user)->toOwn(Post::class)->to('view');
// 或者传递一系列的权限:
Bouncer::allow($user)->toOwn(Post::class)->to(['view', 'update']);
你也可以在应用中允许用户拥有所有类型的模型:
Bouncer::allow($user)->toOwnEverything();
// 或限制指定权限的所有权
Bouncer::allow($user)->toOwnEverything()->to('view');
从用户中撤回角色
Bouncer 也可以从用户中撤回某个预设的角色:
Bouncer::retract('admin')->from($user);
也可以使用用户模型的 retract 方法撤回:
$user->retract('admin');
移除权限
BOuncer 同样可以移除先前授予的权限:
Bouncer::disallow($user)->to('ban-users');
也可以用用户模型的 dissallow 方法撤回:
$user->disallow('ban-users');
注意:如果用户拥有一个允许他们 ban-users 的角色,那么,该用户还是会拥有这个权限,你只有把用户的该角色删除,或者将角色中的 ban-users 权限删除,该用户才不会有 ban-users 权限。
删除角色中的某个已有的权限:
Bouncer::disallow('admin')->to('ban-users');
删除特定模性类型的权限,请将模型名称作为第二个参数传入:
Bouncer::disallow($user)->to('delete', Post::class);
如果用户拥有某个特定的 $post 实例的 delete 权限,以上代码并不会将它的权限删除,你需要通过传入 $post 实例作为第二个参数来删除这个权限,如下:
删除特定模型实例的权限,将实例作为第二参数传入:
Bouncer::disallow($user)->to('delete', $post);
disallow 方法仅仅移除了事先赋予这个用户/角色的权限,如果你想移除一些已被赋予的更为概括的权限的子集,可以使用 forbid 方法。
禁用一项权限
Bouncer 也允许你使用 forbid 方法禁用一项已被赋予的权利,以实现更细致的权限控制。同时,你也许会希望授权用户/角色涵盖了各种操作的权限,随后限制这些操作的一笑部分;
这儿有一个例子:
- 你也许允许用户浏览所有文档,但是有个特殊的高度机密文档不想被他看见:
Bouncer::allow($user)->to('view', Document::class);
Bouncer::forbid($user)->to('view', $classifiedDocument);
- 你也许允许 superadmin 在你的 app 里面做任何事情,包括增加/移除用户。随后你需要一个 admin 角色可以执行除了用户管理的任何事情;
Bouncer::allow('superadmin')->everything();
Bouncer::allow('admin')->everything();
Bouncer::forbid('admin')->toManage(User::class);
- 你也许希望偶尔禁用用户,取消他们被授予的所有权限。然而,通常移除他们所有的角色和权限将意味着重新再授权时,我们要弄清他们的原有权限是什么。
使用禁用能力意味着他们还拥有原来的角色和权限,但是不被允许做任何事情。我们可以通过创建一个特殊的角色--bannde 来实现这一目的。
Bouncer::forbid('banned')->everything();
然后,将想要禁用的用户授予 banned 角色:
Bouncer::assign('banned')->to($user);
移除禁令时,只需要将该角色移除即可:
Bouncer::retract('banned')->from($user);
如你所见,BOouncer的禁用功能将会让你能精细地控制你的 app 中的权限。
检测用户角色
总的来说,你不需要直接检查用户角色。你最好是允许角色拥有某些权限,然后检查这些权限。如果你的需求是粗略的,那么你可以建立一个广泛的权限。比如:检查是否拥有 access-dashboard 权限远比检查是否为 admin 或者 editor 角色要好。当你确实需要检查角色时,以下是检查角色的功能:
检查用户是否有特定的角色:
Bouncer::is($user)->a('moderator');
如果你检查的角色时元音开头,你需要使用 an 别名方法:
Bouncer::is($user)->an('admin');
相反的,你也可以检查用户是或否不具备某个特殊的角色:
Bouncer::is($user)->notA('moderator');
Bouncer::is($user)->notAn('admin');
你还可以检查用户是否拥有众多角色中的一个:
Bouncer::is($user)->a('moderator', 'editor');
你还可以检查用户是否拥有所有给定的角色:
Bouncer::is($user)->all('editor', 'moderator');
你还可以检查用户是否在给定的角色中一个都不具备:
Bouncer::is($user)->notAn('editor', 'moderator');
当然,以上方法都可以在用户实例中直接使用:
$user->isAn('admin');
$user->isA('subscriber');
$user->isNotAn('admin');
$user->isNotA('subscriber');
$user->isAll('editor', 'moderator');
获取用户所有角色
你可以直接从用户模型获取他的所有角色:
$roles = $user->getRoles();
获取用户所有权限
可以直接使用用户模型获取他的所有权限:
$abilities = $user->getAbilities();
这个会返回一个用户权限的集合,包括所有通过角色赋予这个用户的权限。
授权用户
授权用户直接在 Laravel Gate 中或者用户模型($user->can($ability))中处理。
为了更加方便,Bouncer 类提供了以下的直通方法:
Bouncer::can($ability);
Bouncer::cannot($ability);
Bouncer::authorize($ability);
这些方法直接调用 Gate 类。
Blade 指令
Bouncer 不会直接添加它自己的 blade 指令。由于 BOuncer 直接使用 Laravel 的Gate ,你可以直接使用它的 [[[[[[@can](https://learnku.com/users/12729)](https://learnku.com/users/12729)](https://learnku.com/users/12729)](https://learnku.com/users/12729)](https://learnku.com/users/12729)](https://learnku.com/users/12729) 来检查用户的权限;
@if ($user->isAn('admin'))
//
@endif
多租户技术
Bouncer 完全支持多用户 app,在同一个 app 中为所有用户无缝地集成 Bouncer 的角色和权限。
scope 中间件
首先,将 scope 中间件 发布到你的 app 中。
php artisan vendor:publish --tag="bouncer.middleware"
执行完命令,scope 中间件会被发布到 app/Http/Middleware/ScopeBouncer.php
之中,这个中间件是你告诉 Bouncer 当前请求属于哪个租户的地方。
例如,假设你的用户全都都拥有 account_id 属性,那么你的中间件会是这样:
public function handle($request, Closure $next)
{
$tenantId = $request->user()->account_id;
Bouncer::scope()->to($tenantId);
return $next($request);
}
你也可以按需修改这个中间件,比如从子区块获取租户信息。
有了中间件,你需要在 HTTP Kernel 中注册它。
protected $middlewareGroups = [
'web' => [
// 原有的中间件请保存, 然后添加以下这行:
\App\Http\Middleware\ScopeBouncer::class,
]
];
所有的 Bouncer 查询现在将会被指定给特定租户。
自定义 Bouncer scope
根据你的 app 的设置,你也许不想要将所有的查询都作用于当前租户。
例如,你的租户也许有一套相同的固定的角色/权限配置,并且,仅仅允许用户控制为哪些用户分配哪些角色,为哪些角色分配哪些权限。为了实现这个功能,你可以告诉
Bouncer scope 仅限制 Bouncer 的模型之间的关系,而不是模型本身。
Bouncer::scope()->to($tenantId)->onlyRelations();
此外,你的 app 甚至可能不允许用户控制给定角色具有哪些权限。此时,你可以告诉 Bouncer scope 从 scope 中排除角色能力,以便这些关系在所有租户中保持全局统一。
Bouncer::scope()->to($tenantId)->onlyRelations()->dontScopeRoleAbilities();
如果您的需求比上面的概述更专业的话,你可以创建自己的 Scope 来实现你的业务逻辑。
use Silber\Bouncer\Contracts\Scope;
class MyScope implements Scope
{
// 你的 app 所需的自定义的逻辑
}
然后在服务提供者中注册你的自定义 scope:
Bouncer::scope(new MyScope);
Bouncer 将会在它执行的各个地方调用 Scope 中的方法。你可以根据你的特殊需求自由的处理。
配置
Bouncer 附带合理的默认值,因此大多数时候你不需要进行任何配置。对于更细粒度的控制,可以通过调用Bouncer类上的各种配置方法来自定义Bouncer 。
如果你只须有使用其中的一到两项配置选项,你可以将它们粘贴到你的 APPServiceProvider 的 boot 方法中。如果配置需要更多了,你就需要在 app/Providers 目录中创建一个分离的 BouncerServiceProvider 类(记得在 provider 配置数组中进行注册)。
数据表
要更改 Bouncer 使用的数据表名称,你需要传递一个联合数组给 tables
方法。
键名是 Bouncer 的默认表名,值是你要使用的表名。你只需要传递你想修改的表名,而不需要传递所有的表名。
Bouncer::tables([
'abilities' => 'my_abilities',
'permissions' => 'granted_abilities',
]);
Bouncer 发布的迁移使用此配置中的表名,因此请确保在实际运行迁移文件之前这些表存在。
自定义模型
你可以轻松的扩展 Bouncer 的内置 Role 和 Ability 模型:
use Silber\Bouncer\Database\Ability;
class MyAbility extends Ability
{
// custom code
}
use Silber\Bouncer\Database\Role;
class MyRole extends Role
{
// custom code
}
或者,你可以使用 Bouncer 的 IsAbility 和 IsRole 这两个 traits 而不实际扩展任何Bouncer的模型:
use Illuminate\Database\Eloquent\Model;
use Silber\Bouncer\Database\Concerns\IsAbility;
class MyAbility extends Model
{
use IsAbility;
// custom code
}
use Illuminate\Database\Eloquent\Model;
use Silber\Bouncer\Database\Concerns\IsRole;
class MyRole extends Model
{
use IsRole;
// custom code
}
如果你使用这个 traits 方法,请确保设置了正确的 $table 表名和 $fillable 字段。
不管使用哪种方法,下一步,你应该做的就是告诉 Bouncer 你要使用自定义的模型。
Bouncer::useAbilityModel(MyAbility::class);
Bouncer::useRoleModel(MyRole::class);
用户模型
默认情况下,Bouncer 会自动使用默认的用户防护用户模型。
(这里翻译的不是太明白,英语水平有限。请大佬指点:By default, Bouncer automatically uses the user model of the default auth guard.)
如果你将 Bouncer 与非默认防护一起使用,并且它使用的不是同一个用户模型,你需要告诉 Bouncer 你想使用的用户模型;
Bouncer::useUserModel(\App\Admin::class);
所有权
在 Bouncer 中,所有权的概念用于允许用户对他们“拥有”的模型执行操作。
默认情况下,Bouncer 会将模型的 user_id 字段与当前用户的主键进行对比。如果有需要,你可以自行指定字段。
Bouncer::ownedVia('userId');
如果不同模型使用不同字段的所有权,你可以分别注册他们:
Bouncer::ownedVia(Post::class, 'created_by');
Bouncer::ownedVia(Order::class, 'entered_by');
为了获得更好的控制,您可以使用自定义逻辑传递闭包:
Bouncer::ownedVia(Game::class, function ($game, $user) {
return $game->team_id == $user->team_id;
});
FAQ
......
本作品采用《CC 协议》,转载必须注明作者和本文链接
这个tables怎么修改,修改这个tables方法好像没有用
@afoolishman
@afoolishman
@Larwas 谢谢大佬,这段代码应该放在什么地方,我尝试了放在bouncer类的构造函数中,创建角色和权限正常,验证的时候还是显示不正常
请问有实例可以看看嘛