jarhen/laravel-permission

dev-master 2018-08-14 03:44 UTC

This package is not auto-updated.

Last update: 2024-09-19 10:48:58 UTC


README

赞助商

Latest Version on Packagist Build Status StyleCI Total Downloads

此包允许您在数据库中管理用户权限和角色。

一旦安装,您就可以执行以下操作

// Adding permissions to a user
$user->givePermissionTo('edit articles');

// Adding permissions via a role
$user->assignRole('writer');

$role->givePermissionTo('edit articles');

如果您使用多个守卫,我们也为您做好了准备。每个守卫都将有自己的权限和角色集,可以分配给守卫的用户。在readme的使用多个守卫部分了解更多。

因为所有权限都将注册在 Laravel的gate 上,您可以使用Laravel的默认 can 函数测试用户是否具有权限

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

Jarhen是比利时安特卫普的一家网页设计公司。您可以在我们的网站上找到所有开源项目的概述 在这里

安装

Laravel

此包可用于Laravel 5.4或更高版本。如果您使用的是Laravel的较旧版本,请查看此包的v1分支

您可以通过Composer安装此包

composer require jarhen/laravel-permission

在Laravel 5.5中,服务提供程序将自动注册。在框架的较旧版本中,只需将服务提供程序添加到 config/app.php 文件中即可

'providers' => [
    // ...
    Jarhen\Permission\PermissionServiceProvider::class,
];

您可以使用以下命令发布迁移

php artisan vendor:publish --provider="Jarhen\Permission\PermissionServiceProvider" --tag="migrations"

如果您为您的 User 模型使用UUID或GUID,您可以更新 create_permission_tables.php 迁移,并将 $table->morphs('model') 替换为

$table->uuid('model_id');
$table->string('model_type');

迁移发布后,您可以运行迁移来创建角色和权限表

php artisan migrate

您可以使用以下命令发布配置文件

php artisan vendor:publish --provider="Jarhen\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
         * `Jarhen\Permission\Contracts\Permission` contract.
         */

        'permission' => Jarhen\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
         * `Jarhen\Permission\Contracts\Role` contract.
         */

        'role' => Jarhen\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,
];

Lumen

您可以通过Composer安装此包

composer require jarhen/laravel-permission

复制所需的文件

cp vendor/jarhen/laravel-permission/config/permission.php config/permission.php
cp vendor/jarhen/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

然后,在 bootstrap/app.php 中注册中间件

$app->routeMiddleware([
    'auth'       => App\Http\Middleware\Authenticate::class,
    'permission' => Jarhen\Permission\Middlewares\PermissionMiddleware::class,
    'role'       => Jarhen\Permission\Middlewares\RoleMiddleware::class,
]);

以及配置和服务提供程序

$app->configure('permission');
$app->register(Jarhen\Permission\PermissionServiceProvider::class);

现在,运行您的迁移

php artisan migrate

用法

首先,将 Jarhen\Permission\Traits\HasRoles 特性添加到您的 User 模型中

use Illuminate\Foundation\Auth\User as Authenticatable;
use Jarhen\Permission\Traits\HasRoles;

class User extends Authenticatable
{
    use HasRoles;

    // ...
}
  • 请注意,如果您需要在其他模型中使用 HasRoles 特性,例如 Page,您还需要将 protected $guard_name = 'web'; 添加到该模型中,否则您将收到错误
use Illuminate\Database\Eloquent\Model;
use Jarhen\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 Jarhen\Permission\Models\Role;
use Jarhen\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属性。有关详细信息,请参阅readme中的使用多个守卫部分。

HasRoles特性会给您的模型添加Eloquent关系,您可以直接访问它们或用作基础查询。

// get a list of all permissions directly assigned to the user
$permissions = $user->permissions;

// get all permissions inherited via the user's roles
$permissions = $user->getPermissionsViaRoles();

// get a collection of all defined roles
$roles = $user->getRoleNames(); // Returns a collection

HasRoles特性还为您模型的查询添加了一个role范围,用于限定特定角色或权限。

$users = User::role('writer')->get(); // Returns only users with the role 'writer'

role范围可以接受一个字符串、一个\Jarhen\Permission\Models\Role对象或一个\Illuminate\Support\Collection对象。

相同的特性还添加了一个范围,只获取具有特定权限的用户。

$users = User::permission('edit articles')->get(); // Returns only users with the permission 'edit articles' (inherited or directly)

该范围可以接受一个字符串、一个\Jarhen\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');

或者您也可以传递一个表示权限ID的整数

$user->hasPermissionTo('1');
$user->hasPermissionTo(Permission::find(1)->id);
$user->hasPermissionTo($somePermission->id);

您可以测试用户是否具有数组中的任何权限

$user->hasAnyPermission(['edit articles', 'publish articles', 'unpublish articles']);

...或者如果用户具有数组中的所有权限

$user->hasAllPermissions(['edit articles', 'publish articles', 'unpublish articles']);

您也可以传递整数来通过权限ID查找

$user->hasAnyPermission(['edit articles', 1, 5]);

保存的权限将与默认守卫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());

assignRolehasRolehasAnyRolehasAllRolesremoveRole函数可以接受一个字符串、一个\Jarhen\Permission\Models\Role对象或一个\Illuminate\Support\Collection对象。

权限可以被赋予一个角色

$role->givePermissionTo('edit articles');

您可以确定角色是否具有某个特定权限

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

权限可以从角色中撤销

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

givePermissionTorevokePermissionTo函数可以接受一个字符串或一个Jarhen\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();

所有这些响应都是Jarhen\Permission\Models\Permission对象的集合。

如果我们遵循前面的示例,第一个响应将包含delete article权限的集合,第二个将包含edit article权限的集合,第三个将包含两者。

使用Blade指令

此包还添加了Blade指令来验证当前登录用户是否具有给定的角色列表中的所有或任何一个。

可选地,您可以将要检查的guard作为第二个参数传递。

Blade和角色

测试特定角色

@role('writer')
    I am a writer!
@else
    I am not a writer...
@endrole

等同于

@hasrole('writer')
    I am a writer!
@else
    I am not a writer...
@endhasrole

测试列表中的任何角色

@hasanyrole($collectionOfRoles)
    I have one or more of these roles!
@else
    I have none of these roles...
@endhasanyrole
// or
@hasanyrole('writer|admin')
    I am either a writer or an admin or both!
@else
    I have none of these roles...
@endhasanyrole

测试所有角色

@hasallroles($collectionOfRoles)
    I have all of these roles!
@else
    I do not have all of these roles...
@endhasallroles
// or
@hasallroles('writer|admin')
    I am both a writer and an admin!
@else
    I do not have all of these roles...
@endhasallroles

Blade和权限

本包不添加任何特定权限的 Blade 指令。相反,使用 Laravel 的原生 @can 指令来检查用户是否具有特定权限。

@can('edit articles')
  //
@endcan

@if(auth()->user()->can('edit articles') && $some_other_condition)
  //
@endif

使用多个守卫

在使用默认的 Laravel 认证配置时,上述所有方法都将自动生效,无需额外配置。

然而,当使用多个守卫时,它们将充当您的权限和角色的命名空间。这意味着每个守卫都有自己的权限和角色集合,可以分配给其用户模型。

使用多个守卫的权限和角色

当创建新权限和角色时,如果没有指定守卫,则将使用 auth.guards 配置数组中定义的第一个守卫。当为特定守卫创建权限和角色时,您必须在模型上指定其 guard_name

// 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']);

检查用户是否具有特定守卫的权限

$user->hasPermissionTo('publish articles', 'admin');

注意:当确定给定模型上的角色/权限是否有效时,它将按以下顺序选择守卫:$guard_name 属性的模型;然后是配置中的守卫(通过提供者);然后是 auth.guards 配置数组中定义的第一个守卫;然后是 auth.defaults.guard 配置。

将权限和角色分配给守卫用户

您可以使用与上述 使用角色通过权限 中描述的相同方法来将权限和角色分配给用户。只需确保权限或角色上的 guard_name 与用户的守卫相匹配,否则将抛出 GuardDoesNotMatch 异常。

使用多个守卫的 blade 指令

您可以通过将您希望使用的守卫作为指令的第二个参数传递,来使用 使用 blade 指令 中列出的所有 blade 指令。

@role('super-admin', 'admin')
    I am a super-admin!
@else
    I am not a super-admin...
@endrole

使用中间件

此包包含 RoleMiddlewarePermissionMiddleware 中间件。您可以将它们添加到您的 app/Http/Kernel.php 文件中。

protected $routeMiddleware = [
    // ...
    'role' => \Jarhen\Permission\Middlewares\RoleMiddleware::class,
    'permission' => \Jarhen\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 () {
    //
});

或者,您可以使用 |(管道)字符将多个角色或权限分隔开。

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 \Jarhen\Permission\Exceptions\UnauthorizedException) {
        // Code here ...
    }

    return parent::render($request, $exception);
}

使用Artisan命令

您可以使用 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()
    {
        // first include all the normal setUp operations
        parent::setUp();

        // now re-register all the roles and permissions
        $this->app->make(\Jarhen\Permission\PermissionRegistrar::class)->registerPermissions();
    }

数据库播种

关于数据库播种的两个注意事项

  1. 在播种之前最好清除 jarhen.permission.cache,以避免缓存冲突错误。这可以从 artisan 命令(参见后面的故障排除:缓存部分)或直接在播种类中完成(参见下面的示例)。

  2. 以下是一个示例播种器,它清除缓存,创建权限,然后将权限分配给角色

    use Illuminate\Database\Seeder;
    use Jarhen\Permission\Models\Role;
    use Jarhen\Permission\Models\Permission;
    
    class RolesAndPermissionsSeeder extends Seeder
    {
        public function run()
        {
            // Reset cached roles and permissions
            app()['cache']->forget('jarhen.permission.cache');
    
            // create permissions
            Permission::create(['name' => 'edit articles']);
            Permission::create(['name' => 'delete articles']);
            Permission::create(['name' => 'publish articles']);
            Permission::create(['name' => 'unpublish articles']);
    
            // create roles and assign created permissions
    
            $role = Role::create(['name' => 'writer']);
            $role->givePermissionTo('edit articles');
    
            $role = Role::create(['name' => 'moderator']);
            $role->givePermissionTo(['publish articles', 'unpublish articles']);
    
            $role = Role::create(['name' => 'super-admin']);
            $role->givePermissionTo(Permission::all());
        }
    }

扩展

如果您需要扩展现有的 RolePermission 模型,请注意

  • 您的 Role 模型需要扩展 Jarhen\Permission\Models\Role 模型
  • 您的 Permission 模型需要扩展 Jarhen\Permission\Models\Permission 模型

如果您需要替换现有的 RolePermission 模型,您需要考虑以下事项

  • 您的 Role 模型需要实现 Jarhen\Permission\Contracts\Role 接口
  • 您的 Permission 模型需要实现 Jarhen\Permission\Contracts\Permission 接口

在两种情况下,无论是扩展还是替换,您都需要在配置中指定您的新模型。为此,您必须在发布配置后,使用以下命令更新配置文件中的models.rolemodels.permission值。

php artisan vendor:publish --provider="Jarhen\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 jarhen.permission.cache

缓存标识符

提示:如果您正在使用redismemcached等缓存服务,并且您的服务器上运行着其他网站,则可能会遇到缓存冲突。为了防止其他应用程序意外使用/更改您的缓存数据,请在/config/cache.php中为每个应用程序设置唯一的缓存prefix

需要UI吗?

该包本身不附带任何屏幕,您应该自己构建。要开始,请查看Caleb Oki的这篇详细教程

测试

composer test

变更日志

请参阅变更日志以获取有关最近更改的更多信息。

贡献

请参阅贡献指南以获取详细信息。

安全性

如果您发现任何与安全相关的问题,请通过电子邮件freek@jarhen.be与我们联系,而不是使用问题跟踪器。

明信片软件

您可以使用此包,但如果它进入您的生产环境,我们非常希望您从您的家乡给我们寄一张明信片,说明您正在使用我们的哪些包。

我们的地址是:Jarhen,Samberstraat 69D,2060 安特卫普,比利时。

我们将发布所有收到的明信片在我们的公司网站上

致谢

此包主要基于Jeffrey Way的出色Laracasts课程,关于权限和角色。他的原始代码可以在GitHub上的此存储库中找到

特别感谢Alex Vanderbist,他在v2中提供了很大帮助,并感谢Chris Brown长期的支持,帮助我们维护此包。

资源

替代方案

Povilas Korop在Laravel News的一篇文章中很好地列出了替代方案。在相同文章中,他比较了laravel-permission与Joseph Silber的Bouncer,我们认为这也是一个优秀的包。

支持我们

Jarhen是一家总部位于比利时的安特卫普网络设计代理机构。您可以在我们的网站上找到所有开源项目的概述

您的业务是否依赖于我们的贡献?在 Patreon 上联系我们并支持我们。所有承诺都将专门用于分配人力维护和开发新的酷炫功能。

许可证

MIT 许可证 (MIT)。更多信息请参阅 许可证文件