文章转发自专业的Laravel开发者社区,原始连接: https://learnku.com/laravel/t...
这个包容许你在数据库中管理用户的权限和角色。php
当你安装了扩展包以后你就能够这样作:laravel
// 给用户添加一个权限 $user->givePermissionTo('edit articles'); // 经过角色添加权限。 $user->assignRole('writer'); // 给角色添加一个权限 $role->givePermissionTo('edit articles');
若是你给单个用户添加了多个守卫(guard),扩展包也能够处理的很好,每个分配给用户的守卫都有它本身的权限和角色,阅读 using multiple guards章节能够看见更多的信息。git
由于全部的权限将注册在Laravel's gate上,因此你能够调用 Laravel 默认的 'can' 方法来测试用户是否有权限:github
$user->can('edit articles');
Spatie 是一个位于 Antwerp, Belgium的web设计机构。你能够在咱们的官网找到全部的开源项目。web
这个包能够在 Laravel 5.4或更高版本中使用,若是你使用的是旧版本的Laravel,能够切换到 这个包的 v1 分支 去使用。redis
你能够经过 composer 去安装这个包:数据库
composer require spatie/laravel-permission
在 Laravel 5.5 中 service provider 会自动注册,旧版本的Laravel中你须要像如下这样自行添加到 config/app.php
中:bootstrap
'providers' => [ // ... Spatie\Permission\PermissionServiceProvider::class, ];
你可使用如下命令发布 migration :缓存
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider" --tag="migrations"
若是你在 User
模型中使用 UUIDs 或 GUIDs 你能够修改 create_permission_tables.php
migration 并替换 $table->morphs('model')
:安全
$table->uuid('model_id'); $table->string('model_type');
migration发布后,您能够经过运行如下命令来建立角色和权限表:
php artisan migrate
你能够运行如下命令生成配置文件:
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider" --tag="config"
当发布了配置文件后,就能够看到 config/permission.php
中包括:
return [ 'models' => [ /* * When using the "HasRoles" trait from this package, we need to know which * Eloquent model should be used to retrieve your permissions. Of course, it * is often just the "Permission" model but you may use whatever you like. * * The model you want to use as a Permission model needs to implement the * `Spatie\Permission\Contracts\Permission` contract. */ 'permission' => Spatie\Permission\Models\Permission::class, /* * When using the "HasRoles" trait from this package, we need to know which * Eloquent model should be used to retrieve your roles. Of course, it * is often just the "Role" model but you may use whatever you like. * * The model you want to use as a Role model needs to implement the * `Spatie\Permission\Contracts\Role` contract. */ 'role' => Spatie\Permission\Models\Role::class, ], 'table_names' => [ /* * When using the "HasRoles" trait from this package, we need to know which * table should be used to retrieve your roles. We have chosen a basic * default value but you may easily change it to any table you like. */ 'roles' => 'roles', /* * When using the "HasRoles" trait from this package, we need to know which * table should be used to retrieve your permissions. We have chosen a basic * default value but you may easily change it to any table you like. */ 'permissions' => 'permissions', /* * When using the "HasRoles" trait from this package, we need to know which * table should be used to retrieve your models permissions. We have chosen a * basic default value but you may easily change it to any table you like. */ 'model_has_permissions' => 'model_has_permissions', /* * When using the "HasRoles" trait from this package, we need to know which * table should be used to retrieve your models roles. We have chosen a * basic default value but you may easily change it to any table you like. */ 'model_has_roles' => 'model_has_roles', /* * When using the "HasRoles" trait from this package, we need to know which * table should be used to retrieve your roles permissions. We have chosen a * basic default value but you may easily change it to any table you like. */ 'role_has_permissions' => 'role_has_permissions', ], /* * By default all permissions will be cached for 24 hours unless a permission or * role is updated. Then the cache will be flushed immediately. */ 'cache_expiration_time' => 60 * 24, /* * When set to true, the required permission/role names are added to the exception * message. This could be considered an information leak in some contexts, so * the default setting is false here for optimum safety. */ 'display_permission_in_exception' => false, ];
经过 Composer 安装:
composer require spatie/laravel-permission
复制必须的文件:
cp vendor/spatie/laravel-permission/config/permission.php config/permission.php cp vendor/spatie/laravel-permission/database/migrations/create_permission_tables.php.stub database/migrations/2018_01_01_000000_create_permission_tables.php
另一个配置文件 config/auth.php
, 你能够从 Laravel 仓库获取, 或者直接执行下面的命令获取:
curl -Ls https://raw.githubusercontent.com/laravel/lumen-framework/5.5/config/auth.php -o config/auth.php
如今,执行迁移:
php artisan migrate
接下来, 在 bootstrap/app.php
中, 注册中间件:
$app->routeMiddleware([ 'auth' => App\Http\Middleware\Authenticate::class, 'permission' => Spatie\Permission\Middlewares\PermissionMiddleware::class, 'role' => Spatie\Permission\Middlewares\RoleMiddleware::class, ]);
一样的 , 注册配置和服务提供者:
$app->configure('permission'); $app->register(Spatie\Permission\PermissionServiceProvider::class);
首先,添加 Spatie\Permission\Traits\HasRoles
trait 到 User
模型:
use Illuminate\Foundation\Auth\User as Authenticatable; use Spatie\Permission\Traits\HasRoles; class User extends Authenticatable { use HasRoles; // ... }
- 请注意,若是你须要在另外一个模型,例如
Page
中添加HasRoles
trait 你还须要添加protected $guard_name = 'web';
到这个模型中,不然会报错。use Illuminate\Database\Eloquent\Model; use Spatie\Permission\Traits\HasRoles; class Page extends Model { use HasRoles; protected $guard_name = 'web'; // or whatever guard you want to use // ... }
这个包容许用户与权限和角色相关联。每一个角色都与多个权限相关联。Role
和 Permission
都是 Eloquent 模型,它们建立的时候须要传入 name
这个参数,就像下面这样:
use Spatie\Permission\Models\Role; use Spatie\Permission\Models\Permission; $role = Role::create(['name' => 'writer']); $permission = Permission::create(['name' => 'edit articles']);
可使用下面其中一个方法将权限分配给角色:
$role->givePermissionTo($permission); $permission->assignRole($role);
可使用下面其中一种方法将多个权限同步赋予到一个角色:
$role->syncPermissions($permissions); $permission->syncRoles($roles);
可使用如下其中一种方法经过角色去删除权限:
$role->revokePermissionTo($permission); $permission->removeRole($role);
若是你使用多守卫的话, guard_name
必需要设置,在 使用多守卫 段落中有说起到。
HasRoles
trait 具备 Eloquent 模型关系功能,能够经过关系去直接访问或用做基本的查询:
// 获取直接分配给用户的全部的权限 $permissions = $user->permissions; // 返回全部用户经过赋予角色所继承的权限 $permissions = $user->getAllPermissions(); // 获取全部已定义的角色的集合 $roles = $user->getRoleNames(); // 返回一个集合
HasRoles
trait 在你的模型上还增长了 role
scope 能让你检索特定角色或者特定权限的用户:
$users = User::role('writer')->get(); // 返回角色是 'writer' 的用户
role
scope 接收一个字符串, \Spatie\Permission\Models\Role
对象或者 \Illuminate\Support\Collection
对象。
这个 trait 还增长了 scope 让你只能获取到具备某个权限的用户。
$users = User::permission('edit articles')->get(); // 只返回有 'edit articles' 权限的用户 (继承角色得来的或者是直接分配的)
role
scope 接收一个字符串, \Spatie\Permission\Models\Permission
对象或者 \Illuminate\Support\Collection
对象。
分配权限给任何一个用户:
$user->givePermissionTo('edit articles'); // You can also give multiple permission at once $user->givePermissionTo('edit articles', 'delete articles'); // You may also pass an array $user->givePermissionTo(['edit articles', 'delete articles']);
撤销用户的某个权限:
$user->revokePermissionTo('edit articles');
在一次操做中撤销或者新增权限:
$user->syncPermissions(['edit articles', 'delete articles']);
你能够判断某个用户是否具备这个权限:
$user->hasPermissionTo('edit articles');
判断用户是否具备多个权限:
$user->hasAnyPermission(['edit articles', 'publish articles', 'unpublish articles']);
保存了权限后它将会注册在 Illuminate\Auth\Access\Gate
类的默认守卫中。因此你可使用 Laravel 的默认 can
方法来判断用户是否有某个权限:
$user->can('edit articles');
角色能够被分配给任意用户:
$user->assignRole('writer'); // You can also assign multiple roles at once $user->assignRole('writer', 'admin'); // or as an array $user->assignRole(['writer', 'admin']);
角色能够从一个用户身上移除:
$user->removeRole('writer');
角色也能够被同步:
// All current roles will be removed from the user and replaced by the array given $user->syncRoles(['writer', 'admin']);
你能够判断一个用户是否包含某个角色:
$user->hasRole('writer');
你也能够判断一个用户是否包含给定角色列表中的一个:
$user->hasAnyRole(Role::all());
你也能够判断一个用户是否包含全部给定的角色:
$user->hasAllRoles(Role::all());
assignRole
, hasRole
, hasAnyRole
, hasAllRoles
和 removeRole
这些函数能够接受一个字符串, 一个 \Spatie\Permission\Models\Role
对象 或者 一个 \Illuminate\Support\Collection
对象做为参数。
权限能够被分配给一个角色:
$role->givePermissionTo('edit articles');
你能够判断一个角色是否包含某个权限:
$role->hasPermissionTo('edit articles');
权限也能够从一个角色身上移除:
$role->revokePermissionTo('edit articles');
givePermissionTo
和 revokePermissionTo
函数能够接受一个字符串或者一个 Spatie\Permission\Models\Permission
对象做为参数。
权限是从角色中自动继承的.
另外, 我的权限也能够分配给用户.
例如:
$role = Role::findByName('writer'); $role->givePermissionTo('edit articles'); $user->assignRole('writer'); $user->givePermissionTo('delete articles');
在上面的例子中,角色被赋予了编辑文章的权限,而且该角色被分配给了用户。
如今,用户能够编辑、删除文章。“删除”权限是直接分配给用户的直接权限。
当咱们调用 $user->hasDirectPermission('delete articles')
它会返回 true
,
而 false
对应的是 $user->hasDirectPermission('edit articles')
.
若是为应用程序中的角色和用户设置权限,并但愿限制或者更改用户角色的继承权限(仅容许更改用户的直接权限),则这个方法就会很是有用。
你能够列出这些权限:
// Direct permissions $user->getDirectPermissions() // Or $user->permissions; // Permissions inherited from the user's roles $user->getPermissionsViaRoles(); // All permissions which apply on the user (inherited and direct) $user->getAllPermissions();
全部的响应都是 Spatie\Permission\Models\Permission
这个对象的集合.
若是咱们按照以前的例子, 第一个响应将是一个具备 delete article
权限的集合,第二个响应会是一个具备 edit article
权限的集合,而第三个响应将会包含以前两者的集合。
这个包还增长了 Blade 语法来验证当前登陆的用户是否具备所有或某个给定的角色。
你能够经过传入第二个参数 guard
来进行检索。
测试一个特定的角色:
@role('writer') 我是一个 writer! @else 我不是一个 writer... @endrole
至关于
@hasrole('writer') 我是一个 writer! @else 我不是一个 writer... @endhasrole
测试传入的列表中的任一角色:
@hasanyrole($collectionOfRoles) 我有一个或多个这里的权限 @else 这些权限我都没有 @endhasanyrole // or @hasanyrole('writer|admin') 我是一个 writer 或者 admin @else 我既不是 writer 也不是 admin @endhasanyrole
测试是否具备全部角色
@hasallroles($collectionOfRoles) 这些角色我都是 @else 这些角色我都不是 @endhasallroles // or @hasallroles('writer|admin') 我既是 writer 也是 admin @else 我不是 writer 也不是 admin @endhasallroles
本扩展没有提供权限相关的特殊的 Blade directives,而是使用 Laravel 自带的 @can
directive 来校验用户权限。举个栗子:
@can('edit articles') // @endcan
再举个栗子:
@if(auth()->user()->can('edit articles') && $some_other_condition) // @endif
使用 Laravel 默认的 auth 配置时,以上例子的全部的方法均可以正常使用,不须要作额外的配置。
当有多个 guards 时,校验权限和角色时有点像命名空间。意味着每一个 guard 都有与之用户模型相关的的角色和权限。
新增的权限和角色会默认使用系统默认的 guard (config('auth.defaults.guard')
) 。新增权限和角色的时候,能够经过 model 的属性 guard_name
来指定 guard:
// Create a superadmin role for the admin users $role = Role::create(['guard_name' => 'admin', 'name' => 'superadmin']); // Define a `publish articles` permission for the admin users belonging to the admin guard $permission = Permission::create(['guard_name' => 'admin', 'name' => 'publish articles']); // Define a *different* `publish articles` permission for the regular users belonging to the web guard $permission = Permission::create(['guard_name' => 'web', 'name' => 'publish articles']);
校验用户是否有指定 guard 的权限:
$user->hasPermissionTo('publish articles', 'admin');
你可使用上文所述的方法 using permissions via roles 给用户受权和赋予角色。仅须要确保权限或者角色的 guard_name
与用户的 guard 是同样的,不然将会抛出一个GuardDoesNotMatch
异常
全部的 blade directivesusing blade directives 对于多个 guards都是一样适用,只须要将 guard_name
做为第二个参数便可。举个栗子:
@role('super-admin', 'admin') I am a super-admin! @else I am not a super-admin... @endrole
这个包包含 RoleMiddleware
和 PermissionMiddleware
俩个中间件。 你能够把他们添加到 app/Http/Kernel.php
文件中。
protected $routeMiddleware = [ // ... 'role' => \Spatie\Permission\Middlewares\RoleMiddleware::class, 'permission' => \Spatie\Permission\Middlewares\PermissionMiddleware::class, ];
你可使用中间件保护你的路由:
Route::group(['middleware' => ['role:super-admin']], function () { // }); Route::group(['middleware' => ['permission:publish articles']], function () { // }); Route::group(['middleware' => ['role:super-admin','permission:publish articles']], function () { // });
另外,你能够经过 |
(pipe) 字符把多个角色或者权限区分开:
Route::group(['middleware' => ['role:super-admin|writer']], function () { // }); Route::group(['middleware' => ['permission:publish articles|edit articles']], function () { // });
一样, 你也能够经过在构造函数中设置须要的中间件的方式保护你的控制器:
public function __construct() { $this->middleware(['role:super-admin','permission:publish articles|edit articles']); }
若是你想重写默认的 403
响应, 你能够经过应用的异常捕获机制捕获 UnauthorizedException
异常:
public function render($request, Exception $exception) { if ($exception instanceof \Spatie\Permission\Exceptions\UnauthorizedException) { // Code here ... } return parent::render($request, $exception); }
你能够经过控制台使用 artisan 命令建立角色和权限。
php artisan permission:create-role writer
php artisan permission:create-permission "edit articles"
当你为特定的守卫建立角色和权限时,你能够将守卫名字做为第二个参数:
php artisan permission:create-role writer web
php artisan permission:create-permission "edit articles" web
在你应用的测试中,若是你没有在 setUp()
测试方法中填充角色和权限的数据做为测试的一部分,你极可能会遇到先有鸡仍是先有蛋的问题,角色和权限还没注册到门脸上 (由于你测试它们是在门脸注册以后的),解决这个问题很简单:只须要像如下这样在你的测试里面的添加 setUp()
方法来从新注册权限:
public function setUp() { // 首先像正常同样调用如下父类的setUp()方法 parent::setUp(); // 如今从新注册角色和权限 $this->app->make(\Spatie\Permission\PermissionRegistrar::class)->registerPermissions(); }
关于数据库填充有两点须要注意
spatie.permission.cache
,以免缓存冲突的错误,这能够用一条 Artisan 命令解决 (能够参考后面故障排除:缓存部分) 或者直接在一个 seeder 类中清除缓存 (能够看看下面的例子)。这里是一个数据填充示例,它先清除缓存,再建立权限,而后为角色分配权限:
use Illuminate\Database\Seeder; use Spatie\Permission\Models\Role; use Spatie\Permission\Models\Permission; class RolesAndPermissionsSeeder extends Seeder { public function run() { // 重置角色和权限的缓存 app()['cache']->forget('spatie.permission.cache'); // 建立权限 Permission::create(['name' => 'edit articles']); Permission::create(['name' => 'delete articles']); Permission::create(['name' => 'publish articles']); Permission::create(['name' => 'unpublish articles']); // 建立角色并赋予已建立的权限 $role = Role::create(['name' => 'writer']); $role->givePermissionTo('edit articles'); $role->givePermissionTo('delete articles'); $role = Role::create(['name' => 'admin']); $role->givePermissionTo('publish articles'); $role->givePermissionTo('unpublish articles'); } }
若是你想扩展示有的 Role
或者 Permission
模型,请注意:
Role
模型须要继承Spatie\Permission\Models\Role
模型Permission
模型须要继承 Spatie\Permission\Models\Permission
模型若是你须要替换现有的 Role
或者 Permission
模型,请记住:
Role
模型须要实现Spatie\Permission\Contracts\Role
Permission
须要实现 Spatie\Permission\Contracts\Permission
在这两种状况下, 不管是扩展仍是替换, 你须要在配置中指明你的新模型。 为此,你必须在发布配置后,更新在配置文件中的 models.role
和 models.permission
这两个值。经过以下命令:
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider" --tag="config"
角色和权限数据被存在缓存中以加快性能。
当您使用提供的方法来操做角色和权限时,缓存会自动重置:
$user->assignRole('writer'); $user->removeRole('writer'); $user->syncRoles(params); $role->givePermissionTo('edit articles'); $role->revokePermissionTo('edit articles'); $role->syncPermissions(params); $permission->assignRole('writer'); $permission->removeRole('writer'); $permission->syncRoles(params);
然而,若是你直接经过数据库操做权限、角色数据,而不是调用咱们提供的方法,应用程序不会出现你作的更改,除非你手动重置缓存。
如需手动重置此扩展包的缓存,运行命令:
php artisan cache:forget spatie.permission.cache
建议:若是你正在使用诸如 redis
或 memcached
等缓存服务,或者还有其余的网站在你的服务器上运行,你可能会遇到缓存冲突,那么设置本身的缓存前缀是深谋远虑的。
在 / config / cache.php
文件中为每一个应用程序设置独有的标识符。 这将阻止其余应用程序意外使用或更改您的缓存数据。
这个扩展包没有用户界面,你须要本身建立。 请参考 Caleb Oki 的这篇教程。
composer test
请参阅 更新日志 以了解更多最近更新的信息
详情请参阅 贡献代码。
若是您发现任何与安全相关的问题, 请发送邮件至 freek@spatie.be,而不是使用问题跟踪器。
你能够无偿使用此扩展包,但若是你在生产环境中使用,咱们将很是感谢你给咱们发送一张明信片,告诉咱们正在使用哪个扩展包。
咱们的地址是: Spatie, Samberstraat 69D, 2060 Antwerp, Belgium.
咱们把全部收到的明信片发布到了公司官网。
这个扩展包很大程度上基于 Jeffrey Way 很是酷的 Laracasts
关于 权限和角色的课程。这是他的源码地址 in this repo on GitHub.
特别要感谢 Alex Vanderbist ,他对v2版本有过很大帮助, 还有 Chris Brown ,他长期帮助咱们维护着这个扩展包。
Povilas Korop 写的文章 Laravel新闻的一篇文章里作了对比。他用laravel-permission和Joseph Silber的Bouncer)对比, 在咱们的书里也是一个优秀的包。
Spatie是一个web设计机构,在比利时的安特卫普。你能够看到咱们的开源项目的概览 在咱们的网站上。
你的业务依赖于咱们的贡献吗? 在Patreon资助咱们。这些钱将用于维护老产品,开发新产品。
麻省理工学院许可证 (MIT). 有关更多信息,请参阅 许可证文件 。