ferdiunal/nova-shield

一个用于管理权限和角色的 Laravel Nova 扩展包。

v1.0.8 2024-09-21 12:52 UTC

This package is auto-updated.

Last update: 2024-09-21 12:52:52 UTC


README

Nova Shield 通过使用 Spatie Permission 简化了您 Laravel Nova 资源的权限管理。您可以轻松地授予或撤销对特定资源和操作的访问权限,从而简化工作流程并提高安全性。

安装

composer require ferdiunal/nova-shield

配置

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

php artisan vendor:publish --tag nova-shield-config

在配置文件中,您可以通过指定资源参数来控制资源权限,参数可以是 Nova 资源文件夹的路径或字符串类路径。

例如,在下面的代码中,我们定义了资源和相应的策略

显示代码
<?php

return [
    /**
     * Specify the resources that will be used in the project.
     * If you want to use custom resources, you can add them to the list.
     */
    'resources' => [
        app_path('Nova'),
        \Ferdiunal\NovaShield\Http\Nova\ShieldResource::class,
        // Custom resource: For custom menu items
        // [
        //     "name" => "Custom Menu Item",
        //     "prefix" => "customMenuItem::",
        //     "policies" => ["CustomMenuPolicy"] // Add custom menu policies here
        // ]
    ],

    // 'teamFields' => \App\Lib\TeamField::class,

    /**
     * Constant policies of Laravel Nova
     */
    'policies' => [
        'viewAny',
        'view',
        'create',
        'update',
        'replicate',
        'delete',
        'restore',
        'forceDelete',
        'runAction',
        'runDestructiveAction',
        'canImpersonate',
        'canBeImpersonated',
        'add{Model}',
        'attach{Model}',
        'attachAny{Model}',
        'detach{Model}',
    ],

    /**
     * Specify the file path of each language files for authorisations.
     */
    'langs' => [
        // lang_path('en/nova-shield.json'),
        // base_path('langs/en/nova-shield.json'),
    ],

    /**
     * Default Super admin role name and guard
     */
    'superAdmin' => [
        'name' => 'super-admin',
        'guard' => 'web',
    ],

    'hooks' => [
        /**
         * When matching permissions with roles, upsert is used by default.
         * If you are using custom ID types like UUID or ULID, you need to include them in the upsert operation.
         * Therefore, you can write and use a query that suits your project needs.
         */
        'permission' => \Ferdiunal\NovaShield\Lib\DefaultPermissionHook::class,
    ],
];

自定义菜单配置

该包的主要目的是管理 Nova 资源的权限,但我意识到还需要自定义菜单的支持。必要的开发工作已经完成。您可以参考以下用法来实现自定义菜单。

    // app/Providers/NovaServiceProvider.php
    Nova::mainMenu(function (Request $request) {
        return [
            MenuItem::make('Custom Menu Item')
                ->path('/custom-menu')
                ->canSee(
                    function ($request) {
                        return $request->user()->can('CustomMenuPolicy');
                    }
                )
        ];
    });

    // ----

    // config/nova-shield.php
    return [
        "resources" => [
            ...
            // Custom resource: For custom menu items
            [
                "name" => "Custom Menu Item",
                "prefix" => "customMenuItem::",
                "policies" => ['CustomMenuPolicy'] // Add custom menu policies here
            ]
        ]
    ];

然后按照以下方式编辑 App\Nova\Resource.php 文件。

<?php

namespace App\Nova;

use Ferdiunal\NovaShield\PermissionAuthorizable;
use Laravel\Nova\Resource as NovaResource;

abstract class Resource extends NovaResource
{
    use PermissionAuthorizable;
    ....
}

团队支持

我假设您已经为 Spatie Permission 完成了团队集成,并且您可以按照以下设置进行 NovaShield 的配置。

模型集成

团队功能在每个项目中都不同,请根据您的项目填写相关方法。

// App\Models\User

use Ferdiunal\NovaShield\Contracts\HasShieldTeam;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable implements HasShieldTeam
{
    public function getTeamIdAttribute(): mixed
    {
        // return $this->team_id
    }
}

添加团队字段

考虑到团队功能在每个项目中都可能不同,您需要自己添加团队字段。

namespace App\Lib;

use Ferdiunal\NovaShield\Lib\NovaTeamHelperField;
use Laravel\Nova\Fields\Field;
use Laravel\Nova\Fields\Select;

class TeamField extends NovaTeamHelperField
{
    public static function field(): Field
    {
        return Select::make('Teams', 'team_id')
            ->options([])
            ->displayUsingLabels()
            ->searchable()
            ->sortable();
    }
}

添加 Nova 路由中间件

添加 TeamMiddleware 到 nova 路由

return [

    /*
    |--------------------------------------------------------------------------
    | Nova Route Middleware
    |--------------------------------------------------------------------------
    |
    | These middleware will be assigned to every Nova route, giving you the
    | chance to add your own middleware to this stack or override any of
    | the existing middleware. Or, you can just stick with this stack.
    |
    */

    'middleware' => [
        ....
        \Ferdiunal\NovaShield\Http\Middleware\TeamMiddleware::class,
    ],
];

命令

该包包含两个不同的命令。第一个命令检查超级管理员角色是否存在,如果不存在则创建它,并将配置文件中指定的资源权限分配给它。第二个命令用于将超级管理员角色分配给用户。

同步超级管理员角色和权限命令

php artisan artisan nova-shield:sync-super-admin

将超级管理员角色分配给用户命令

php artisan nova-shield:super-admin

权限同步钩子

在将权限映射到角色时,默认使用 upsert。如果您使用自定义 ID 类型(如 UUID 或 ULID),则 upsert 无法识别这些 ID。因此,您可以编写并使用适合项目需求的自定义查询。

示例钩子:

// app/SyncPermissionHook.php

<?php

namespace App;

use Ferdiunal\NovaShield\Contracts\SyncPermissionHook as SyncPermissionHookContract;
use Illuminate\Support\LazyCollection;
use Illuminate\Support\Str;
use Spatie\Permission\Contracts\Role;
use Spatie\Permission\Models\Permission;

class SyncPermissionHook implements SyncPermissionHookContract
{
    /**
     * Sync permissions to a role
     *
     * @param  array<int,string>  $permissions
     * @return void
     */
    public function __invoke(Role $role, $permissions)
    {
        Permission::query()->upsert(
            LazyCollection::make($permissions)
                ->map(function ($permission) use (&$role) {
                    return [
                        'id' => Str::uuid(),
                        'name' => $permission,
                        'guard_name' => $role->guard_name,
                        'created_at' => now(),
                        'updated_at' => now(),
                    ];
                })->toArray(),
            ['name', 'guard_name'],
            ['name', 'guard_name'],
        );

        $role->syncPermissions($permissions);
    }
}

您需要将配置文件中创建的类替换为默认类。

示例:

// config/nova-shield.php

return [
    'hooks' => [
        /**
         * When matching permissions with roles, upsert is used by default.
         * If you are using custom ID types like UUID or ULID, you need to include them in the upsert operation.
         * Therefore, you can write and use a query that suits your project needs.
         */
        'permission' => \App\SyncPermissionHook::class,
    ],
];

屏幕截图

许可协议 本软件包是开源软件,根据 MIT 许可协议 许可。