coucounco/laravel-acl

此包的最新版本(v3.0.0)没有可用的许可证信息。

Laravel 访问控制列表

v3.0.0 2024-09-09 09:36 UTC

README

Latest Stable Version Total Downloads

这是一个为 Laravel 6.0|7.0|8.0|9.0 提供访问控制列表的包。

对于 Laravel 6.0|7.0|8.0 使用 v1 版本。

对于 Laravel 9.0 使用 v2 版本。

入门指南

此包可以通过 Composer 安装

composer require coucounco/laravel-acl

安装后,您必须执行以下步骤

1) 在 config/app.php 文件中添加服务提供者

'providers' => [
    // ...
    coucounco\LaravelAcl\ServiceProvider::class,
];

2) 在您的应用程序中发布 laravel-acl 配置

此步骤将复制配置文件到您的 Laravel 应用配置文件夹中。

  • config/acl.php
  • config/acl/users.php
php artisan vendor:publish --provider="coucounco\LaravelAcl\ServiceProvider"

发布后,您可以通过 config/acl.php 文件管理 laravel-acl 的配置,它包含

<?php
return [

    /*
     * Defaults for laravel-acl
     */
    'defaults' => [
        /**
         * The acls consists in a set of permissions for a given entity.
         * Here you can set the default acls (acls defined in the models section of this config file) used by laravel-acl
         */
        'acls' => 'users',
    ],

    /**
     * Here you map models to acls.
     *
     * You can add new row by adding :
     *      [Model] => [acls_name]
     *
     * After adding a new line here, you will need to add a new configuration files under config/acl/[acls_name].php
     */
    'models' => [
        App\Models\User::class => 'users',
    ],

    /**
     * Cache configuration
     */
    'cache' => [
        'enable' => true,
        'key' => 'laravel-acl_',
        'store' => '',
        'expiration_time' => 432000
    ],
];

3) 配置 acls

laravel-acl 不仅提供 acls 和权限给一个模型(默认 App\Models\User),还可以配置多个。默认情况下,使用 users 模型,使用模型 App\Models\User。但您可以根据需要添加更多 acls。

    'defaults' => [
        'acls' => 'users',
    ],
    'models' => [
        App\Models\User::class => 'users',
    ],

示例

    'defaults' => [
        'acls' => 'users',
    ],
    'models' => [
        App\Models\User::class => 'users',
        App\Models\Member::class => 'members',
    ],

每个 acls 都有一个相关的配置文件。 usersconfig/acl/users.php 并包含以下内容

<?php
return [
    /**
     * Register every permissions here
     * key is the name of the permission
     * value is the id of the permission
     * Every permissions can have a different access level
     *    0 = ACL_NONE    -> no permission
     *    1 = ACL_READ    -> read permission
     *    2 = ACL_CREATE  -> create permission
     *    3 = ACL_UPDATE  -> update permission
     *    4 = ACL_DELETE  -> delete permission
     * Access level are incrmental. If user has a permission with an access level of ACL_CREATE
     * it means that the user can ACL_READ and ACL_CREATE
     */
    'permissions' => [
        'superadmin' => 0,
        'user' => 1,
        'group' => 2,
        'page' => 3,
    ],

    /**
     *
     */
    'roles' => [
        'admins' => "1",
        'user' => "0",
    ],

    'model' => [
        // direct acl on user
        'user' => [
            /**
             * Enable acl for user
             */
            'enableAcl' => true,
            /**
             * The attribute where the acl is stored in the User model.
             * It's basically the name of the column in the database
             */
            'attributeName' => 'acl',
        ],
        // acl via groups of user
        // n-n relation between user and group
        'group' => [
            /**
             * Enable acl for group
             */
            'enableAcl' => false,
            /**
             * The name of the relationship from the User model to the "group" model
             */
            'relationship' => 'groups',
            /**
             * The attribute where the acl is stored in the "group" model.
             * It's basically the name of the column in the database
             */
            'attributeName' => 'acl',
        ]
    ],

    'cache' => [
        'key' => 'laravel-acl_',
        'store' => '',
        'expiration_time' => 432000
    ]
];

3) 配置用户 ACL

可选地,您可以在 User 上启用直接 acl

要启用此功能,您必须编辑 config/acl/users.php 文件中的 model.user.enableAcl 并执行以下说明。

如果您不想在用户上启用直接 acl,请跳到下一章。

3.1) 更新 User 模型

在您的 User 模型中添加 UserAcl 特性。

namespace App;

...
use coucounco\LaravelAcl\Traits\UserAcl;

class User extends Model {
    use UserAcl;

    ...    
}

3.2) 在 users 表中添加 acl 列

创建一个新的迁移文件以更新 users

php artisan make:migration add_acl_in_users_table --table=users

并添加新列

<?php
   
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class AddAclInUsersTable extends Migration
{
   /**
    * Run the migrations.
    *
    * @return void
    */
   public function up()
   {
       Schema::table('users', function (Blueprint $table) {
            $table->text('acl')->nullable();
       });
   }

   /**
    * Reverse the migrations.
    *
    * @return void
    */
   public function down()
   {
       Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('acl');
       });
   }
}

默认情况下,此列的名称为 acl,但您可以通过在 config/acl/users.php 文件和此迁移文件中更新 model.user.attributeName 来更改它。

4) 配置组 ACL

可选地,您可以启用组 acl。

要启用此功能,您必须编辑 config/acl/users.php 文件中的 model.user.enableAcl 并执行以下说明。

如果您不想在用户上启用直接 acl,请跳到下一章。

4.1) 设置数据库表

要启用组 acl,您必须创建更多表或更新现有的表。

您需要一个 groups 表和中间表 group_user 以创建多对多关系。(如果您有不同的命名方式也行)

如果您需要创建这些表,请按照第 4.1.1 节进行操作,否则按照 4.1.2 节进行操作。

4.1.1) 创建表

如果您已经有一个与 User 的多对多关系相似的分组表,则不要创建这些表。

创建一个新的迁移文件以创建 groups

php artisan make:migration create_groups_table

内容如下

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateGroupsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('groups', function (Blueprint $table) {
            $table->bigIncrements('id');
            $this->string('name');
            $this->text('acl')->nullable();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('groups');
    }
}

可以更改 acl 列的名称,方法是在 config/acl/users.php 文件和此迁移文件中更新 model.group.attributeName

添加一个新的迁移文件以创建名为 group_user 的中间表

php artisan make:migration create_group_user_table

内容如下

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateGroupUserTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('group_user', function (Blueprint $table) {
            $table->unsignedBigInteger('user_id');
            $table->unsignedBigInteger('group_id');

            $table->foreign('user_id')
                ->references('id')->on('users');

            $table->foreign('group_id')
                ->references('id')->on('groups');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('group_user');
    }
}

这就是创建数据库表的全部内容。

4.1.2) 更新表

在您的分组表中添加 acl 列。

创建一个新的迁移文件以更新您的分组表。

确保您有正确的表名。

php artisan make:migration add_acl_in_groups_table --table=groups

并添加新列

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class AddAclInUsersTable extends Migration
{
   /**
    * Run the migrations.
    *
    * @return void
    */
   public function up()
   {
       Schema::table('groups', function (Blueprint $table) {
            $table->text('acl')->nullable();
       });
   }

   /**
    * Reverse the migrations.
    *
    * @return void
    */
   public function down()
   {
       Schema::table('groups', function (Blueprint $table) {
            $table->dropColumn('acl');
       });
   }
}

默认情况下,此列的名称为 acl,但您可以通过在 config/acl/users.php 文件和此迁移文件中更新 model.group.attributeName 来更改它。

数据库表更新完成。

4.2) 更新群组模型

在你的Group模型中添加GroupAcl特质。你还需要将关系添加到User模型。

namespace App\Models;

...
use coucounco\LaravelAcl\Traits\GroupAcl;

class Group extends Model
{
    use GroupAcl;

    ...

    public function users() {
        return $this->belongsToMany('App\User');
    }
}

4.3) 更新User模型

将关系添加到User模型。

如果你的群组表有不同的名称,这没有问题。你只需更新model.group.relationship,并在config/acl/users.php文件中的关系函数上设置此名称。

namespace App;

class User extends Model {

    ...    

    public function groups() {
        return $this->belongsToMany('App\Group');
    }

}

5) 享受吧!

一切准备就绪,现在跳转到文档部分,了解更多关于laravel-acl的信息。

文档

本章解释了laravel-acl是如何工作的,并描述了可用的工具(助手、中间件等)。

定义权限和角色

权限和角色以硬编码的方式在config/acl/users.php文件中管理。这个选择是为了简化使用并尽可能避免数据库查询。

权限

您可以通过在config/acl/users.php文件中的permissions数组中添加新条目轻松添加权限。

键是权限的名称,值是标识符

必须有一个superadmin权限,其标识符设置为0

您可以按照自己的方式管理其他所有权限。

'permissions' => [
        'superadmin' => 0,
        'user' => 1,
        'group' => 2,
        'page' => 3,
        
        'run_page_import' => 9,
    ],

角色

角色是一组预置权限。您可以使用config/acl/users.php文件中的roles数组来管理角色。

键是角色的名称,值是ACL

'roles' => [
    'admins' =>     "1",
    'user' =>   "4110",
],

ACL

什么是ACL?

这是一个字符串值,用于定义用户或组的权限。

默认情况下,此值存储在users表的acl列和群组表中。

让我们以下面的ACL为例。

"1000003410"

如果我们定义了以下权限。

'permissions' => [
        'superadmin' => 0,
        'user' => 1,
        'group' => 2,
        'page' => 3,

        'run_page_export' => 8,        
        'run_page_import' => 9,
    ],

ACL是从右到左读取的。

每个数字代表什么?

  • ACL“1000003410”中的第一个数字“0”代表标识符为“0”的权限。在我们的例子中是superadmin权限。
  • 第二个数字“1”代表标识符为“1”的权限(这是user权限)。
  • 第四个数字“3”代表page权限。
  • 第八个数字“0”代表run_page_export权限。
  • 最后一个数字(第九个)是“1”,代表run_page_import权限。

但是,这些值“0”、“1”、“2”、“3”、“4”在每个数字上代表什么?

这些值定义了给定权限的访问级别。

所以,描述ACL“1000003410”,用户有以下权限/限制

  • 用户不是superadmin
  • 用户对user权限有读访问权限;
  • 用户对group权限有删除访问权限;
  • 用户对page权限有更新访问权限;
  • 用户不能执行run_page_export
  • 并且用户允许执行run_page_import

您已经了解了关于权限、角色和ACL的所有内容。跳到下一章学习如何授予和撤销权限

授予和撤销权限

给用户

如何给用户授予superadmin权限

$user->grantPermission('superadmin', ACL_ALLOW);
$user->save();

如果不保存,权限将不会持久化到数据库中。

如何给用户授予对group权限的读访问权限

$user->grantPermission('group', ACL_READ);
$user->save();

如何给用户授予对page权限的删除访问权限

$user->grantPermission('page', ACL_DELETE);
$user->save();

如何一次性授予多个权限

$user->grantPermissions([
    'page' => ACL_READ,
    'user' => ACL_UPDATE
 ]);
$user->save();

如何撤销权限

$user->revokePermission('user');
$user->save();

或者您也可以授予ACL_NONEACL_DENY级别。

$user->grantPermission('user', ACL_DENY);
$user->save();

如何撤销多个权限

$user->revokePermissions(['user', 'group']);
$user->save();

如何撤销所有权限

$user->revokePermissions();
$user->save();

给群组

它与用户的方式相同。

$group->grantPermission('user', ACL_READ);
$group->save();

$group->grantPermissions([
    'user' => ACL_READ,
    'page' => ACL_UPDATE,
    'run_page_export' => ACL_ALLOW
]);
$group->save();

$group->revokePermission('user');
$group->save();

$group->revokePermissions(['user', 'run_page_export']);
$group->save();

现在您已经学会了如何授予和撤销用户或组的权限,接下来您需要学习如何检查用户的权限。

检查访问权限

本章描述了检查用户是否有权限访问页面或执行操作的每一种方法。

权限门

您可以使用由laravel提供的Gate门面。

Gate::allows('user', [ACL_CREATE]);

用户模型

您可以使用Laravel中的can方法来检查User权限。

检查用户是否能读取页面

$hasPermission = auth()->user()->can('page', [ACL_READ]);

如果用户能够读取页面,则返回true,否则返回false。

检查用户是否在给定组的作用域内可以编辑用户

$group = Group::find(1);

$hasPermission = auth()->user()->can('page', [ACL_READ, $group]);

只有当用户获得给定组的访问权限时才返回true,否则返回false。

这对于管理与特定组相关联的实体的访问非常有用。

检查用户是否在多个组的作用域内可以更新页面

$group1 = Group::find(1);
$group2 = Group::find(12);

$hasPermission = auth()->user()->can('page', [ACL_READ, collect([$group1, $group2])]);

第二个参数(组)必须是Illuminate\Support\Collection集合。

中间件

您可以使用laravel-acl提供的acl中间件来直接在路由文件(routes/web.php)中保护路由或整个资源。

限制具有给定权限和级别的用户的访问

Route::get('users/index', 'UserController@index')->name('users.index')->middleware('acl:user:1');

此路由将只允许具有user权限且具有ACL_READ级别的用户访问。

限制具有给定权限和级别的用户的访问

Route::get('users/index', 'UserController@index')->name('users.index')->middleware('acl:user:1|group:1');

此路由将只允许具有user权限且具有ACL_READ级别或具有group权限且具有ACL_READ级别的用户访问。

Blade

在blade视图中隐藏一些按钮很有用。为了实现这一点,您可以使用Laravel提供的一些指令。

@can blade指令
@can('user', [ACL_READ])
    allow
@else
    denied
@endcan

等同于编写

@if(auth()->user()->can('user', [ACL_READ]))
    allow
@else
    denied
@endif
@cannot blade指令
@cannot('user', [ACL_READ])
    denied
@else
    allow
@endcannot
@canany blade指令
@canany(['user', 'page'], [ACL_READ])
    The user has page or user permisson with a read level
@elsecanany(['group'], ACL_READ)
    Or the user has the group permission with a read level
@else
    denied
@endcannot

辅助函数

检查权限

检查用户是否能读取页面

acl_has_permission($user, 'page', ACL_READ)
检索权限和角色

您可以使用辅助方法检索所有权限。

$permissions = acl_permissions()

获取其他acls的权限,只需传递acls的名称作为参数acl_permissions('members')

您可以使用辅助方法检索所有角色。

$roles = acl_roles()

获取其他acls的角色,只需传递acls的名称作为参数acl_permissions('members')

strict选项

有时,您可能希望检查用户是否严格拥有权限。

这是什么意思?

示例

  • $user1拥有superadmin权限
  • $user2拥有is_manager权限

因此,当您检查$user1是否具有is_manager权限时

$user1->can('is_manager');

即使他没有is_manager权限,因为他是superadmin,这也会返回true

可以使用具有严格参数的权限进行检查。

$user1->can('is_manager', ACL_STRCT);

即使用户是superadmin,这也会返回false

$user2->can('is_manager', ACL_STRCT);

这会返回true,因为$user2拥有is_manager权限。