rupadana/filament-shield

为 `spatie/laravel-permission` 提供的丝材支持。

3.0.5 2023-10-11 05:10 UTC

This package is auto-updated.

Last update: 2024-09-15 07:20:44 UTC


README

filament-shield-art

FILAMENT 8.x Packagist Tests Passing Code Style Passing Downloads

盾牌

为您的 Filament Admin 添加访问管理最容易且最直观的方式

  • 🔥 资源
  • 🔥 页面
  • 🔥 小部件
  • 🔥 自定义权限

注意

对于 Filament 2.x 请使用 2.x 分支

重要

v3.1.0 之前,Shield 支持 spatie/laravel-permission:^5.0,现在它支持版本 ^6.0。这涉及到一些关于迁移的破坏性更改。如果您是从 v3.1.0 之前的版本升级,请确保删除旧迁移文件并重新发布新的迁移文件。

安装

  1. 通过 composer 安装此包
composer require bezhansalleh/filament-shield
  1. Spatie\Permission\Traits\HasRoles 特性添加到您的用户模型中
use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Permission\Traits\HasRoles;

class User extends Authenticatable
{
    use HasRoles;

    // ...
}
  1. 发布 config 文件,然后设置您的配置
php artisan vendor:publish --tag=filament-shield-config
  1. 为所需的 Filament 面板注册插件
public function panel(Panel $panel): Panel
{
    return $panel
        ->plugins([
            \BezhanSalleh\FilamentShield\FilamentShieldPlugin::make()
        ]);
}
  1. 现在运行以下命令安装 shield
php artisan shield:install

按照提示操作,并享受使用体验!

Filament 面板

如果您想为多个面板启用 Shield,则需要像上面提到的那样为每个面板注册插件。

面板访问

Shield 包含 HasPanelShield 特性,该特性提供了一种简单的方法来将 Shield 的约定与 Filament 的面板访问系统集成。

HasPanelShield 特性为 canAccessPanel 方法提供了一种实现,它根据用户是否具有 super_admin 角色或 panel_user 角色来确定访问权限。它还在创建用户时分配 panel_user 角色并在删除时移除它。当然,角色名称可以从插件的配置文件中更改。

use BezhanSalleh\FilamentShield\Traits\HasPanelShield;
use Filament\Models\Contracts\FilamentUser;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Permission\Traits\HasRoles;

class User extends Authenticatable implements FilamentUser
{
    use HasRoles;
    use HasPanelShield;
    // ...
}

资源

一般来说,Shield 处理了两种情况下您的 Filament 资源的权限。

默认

默认情况下,Shield 处理 Filament 资源预定义的权限。所以如果您只需要这些,您就设置好了。如果您需要添加单个权限(例如 lock),并且希望它在所有资源中都可用,只需将其追加到以下 config

    permission_prefixes' => [
        'resource' => [
            'view',
            'view_any',
            'create',
            'update',
            'restore',
            'restore_any',
            'replicate',
            'reorder',
            'delete',
            'delete_any',
            'force_delete',
            'force_delete_any',
            'lock'
        ],
        ...
    ],

💡 现在您可能在想 如果我只需要一个权限仅适用于一个资源怎么办? 没关系,这正是 自定义权限 发挥作用的地方。

自定义权限

为了为每个 Resource 定义自定义权限,您的 Resource 必须实现 HasShieldPermissions 合约。此合约有一个 getPermissionPrefixes() 方法,该方法返回一个包含您的 Resource 权限前缀的数组。

假设您有一个 PostResource,并且您想要几个预定义的权限以及一个名为 publish_posts 的新权限,这些权限仅适用于 PostResource

<?php

namespace BezhanSalleh\FilamentShield\Resources;

use BezhanSalleh\FilamentShield\Contracts\HasShieldPermissions;
...

class PostResource extends Resource implements HasShieldPermissions
{
    ...

    public static function getPermissionPrefixes(): array
    {
        return [
            'view',
            'view_any',
            'create',
            'update',
            'delete',
            'delete_any',
            'publish'
        ];
    }

    ...
}

在上面的示例中,getPermissionPrefixes() 方法返回 Shield 需要生成的权限前缀。

✅ 现在要强制执行 publish_post 权限,请转到您的 PostPolicy 并添加一个 publish() 方法

    /**
     * Determine whether the user can publish posts.
     *
     * @param  \App\Models\User  $admin
     * @return \Illuminate\Auth\Access\Response|bool
     */
    public function publish(User $user)
    {
        return $user->can('publish_post');
    } 

🅰️/🈯️ 要使前缀可翻译,发布 Shield 的翻译,并在 resource_permission_prefixes_labels 中将前缀作为键,将翻译作为值附加到您需要的语言。

//lang/en/filament-shield.php
'resource_permission_prefixes_labels' => [
    'publish' => 'Publish'    
],
//lang/es/filament-shield.php
'resource_permission_prefixes_labels' => [
    'publish' => 'Publicar'    
],
配置权限标识符

默认情况下,权限标识符的生成方式如下

Str::of($resource)
    ->afterLast('Resources\\')
    ->before('Resource')
    ->replace('\\', '')
    ->snake()
    ->replace('_', '::');

例如,如果您有一个如 App\Filament\Resources\Shop\CategoryResource 的资源,则权限标识符将是 shop::category,然后它会带有您定义的前缀或默认的 Shield 前缀。

如果您想更改默认行为,则可以在服务提供者的 boot() 方法中调用静态 configurePermissionIdentifierUsing() 方法,并向其传递一个闭包以修改逻辑。闭包接收资源的完全限定类名作为 $resource,这使得您能够访问资源中定义的任何属性或方法。

例如,如果您想使用模型名称作为权限标识符,可以这样做

use BezhanSalleh\FilamentShield\Facades\FilamentShield;

FilamentShield::configurePermissionIdentifierUsing(
    fn($resource) => str($resource::getModel())
        ->afterLast('\\')
        ->lower()
        ->toString()
);

警告 请记住,确保权限标识符的唯一性现在取决于您。

自定义导航组

默认情况下,英文翻译将角色和权限显示为 'Filament Shield' 下的内容。如果您想更改这一点,首先发布 翻译文件 并更改相关区域设置为您的选择组,例如

'nav.group' => 'Filament Shield',

改为

'nav.group' => 'User Management',

将此应用到您有组的每种语言中。

页面

如果您为 Pages 生成权限,您可以切换侧边栏中的页面导航和页面的受限访问。您可以手动设置此操作,但此包附带了一个 HasPageShield 特性来加快此过程。您只需在您的页面中使用此特性即可。

<?php

namespace App\Filament\Pages;

use ...;
use BezhanSalleh\FilamentShield\Traits\HasPageShield;

class MyPage extends Page
{
    use HasPageShield;
    ...
}

📕 HasPageShield 使用 booted 方法检查用户的权限,并确保在父页存在的情况下执行 booted 页面方法。

页面钩子

但是,如果您需要在 booted 方法前后执行某些方法,您可以在您的 Filament 页面中声明下一个钩子方法。

<?php

namespace App\Filament\Pages;

use ...;
use BezhanSalleh\FilamentShield\Traits\HasPageShield;

class MyPage extends Page
{
    use HasPageShield;
    ...

    protected function beforeBooted : void() {
        ...
    }

    protected function afterBooted : void() {
        ...
    }

    /**
     * Hook to perform an action before redirect if the user
     * doesn't have access to the page.  
     * */
    protected function beforeShieldRedirects : void() {
        ...
    }
}
页面重定向路径

HasPageShield 默认使用 config('filament.path') 值进行 Shield 重定向。如果您需要覆盖重定向路径,只需将下一个方法添加到您的页面即可。

<?php

namespace App\Filament\Pages;

use ...;
use BezhanSalleh\FilamentShield\Traits\HasPageShield;

class MyPage extends Page
{
    use HasPageShield;
    ...

    protected function getShieldRedirectPath(): string {
        return '/'; // redirect to the root index...
    }
}

小部件

如果您为 Widgets 生成权限,您可以根据用户是否有权限切换它们的状态。您可以手动设置此操作,但此包附带了一个 HasWidgetShield 特性来加快此过程。您只需在您的部件中使用此特性即可。

<?php

namespace App\Filament\Widgets;

use ...;
use BezhanSalleh\FilamentShield\Traits\HasWidgetShield;

class IncomeWidget extends LineChartWidget
{
    use HasWidgetShield;
    ...
}

策略

角色策略

为了确保通过 RolePolicy 访问 RoleResource,您需要在您的 AuthServiceProvider 中添加以下内容

//AuthServiceProvider.php
...
protected $policies = [
    'Spatie\Permission\Models\Role' => 'App\Policies\RolePolicy',
];
...

如果您已在 config 中启用它,则可以跳过此步骤。

// config/filament-shield.php
...

'register_role_policy' => [
    'enabled' => true,
],
...

策略路径

如果您的策略不在 app_path() 中的默认 Policies 目录中,您可以在配置文件中更改目录名称。

...
'generator' => [
    'option' => 'policies_and_permissions',
    'policy_directory' => 'Policies',
],
...

为模型或第三方插件自定义文件夹结构

Shield 还为具有自定义文件夹结构的第三方插件和 Models 生成策略和权限,为了强制执行生成的策略,您需要在应用程序的 AuthServiceProvider 中注册它们。

...
class AuthServiceProvider extends ServiceProvider
{
    ...
    protected $policies = [
        ...,
        'App\Models\Blog\Author' => 'App\Policies\Blog\AuthorPolicy',
        'Ramnzys\FilamentEmailLog\Models\Email' => 'App\Policies\EmailPolicy'

    ];

用户(将角色分配给用户)

Shield 默认不提供将角色分配给用户的方式,但是您可以使用 Filament FormsSelectCheckboxList 组件轻松地将角色分配给用户。在您的用户 Resource 的表单中添加这些组件之一,并按需配置它们。

// Using Select Component
Forms\Components\Select::make('roles')
    ->relationship('roles', 'name')
    ->multiple()
    ->preload()
    ->searchable()
                    
// Using CheckboxList Component
Forms\Components\CheckboxList::make('roles')
    ->relationship('roles', 'name')
    ->searchable()

您可以在 Filament 文档 中了解更多关于这些组件的信息。

布局自定义

您可以在不发布资源的情况下轻松自定义 GridSectionCheckboxListcolumns()columnSpan()

use BezhanSalleh\FilamentShield\FilamentShieldPlugin;

public function panel(Panel $panel): Panel
{
        return $panel
            ...
            ...
            ->plugins([
                FilamentShieldPlugin::make()
                    ->gridColumns([
                        'default' => 1,
                        'sm' => 2,
                        'lg' => 3
                    ])
                    ->sectionColumnSpan(1)
                    ->checkboxListColumns([
                        'default' => 1,
                        'sm' => 2,
                        'lg' => 4,
                    ])
                    ->resourceCheckboxListColumns([
                        'default' => 1,
                        'sm' => 2,
                    ]),
            ]);
}
Screenshot 2023-09-24 at 10 34 31 PM

翻译

使用以下方法发布翻译:

php artisan vendor:publish --tag="filament-shield-translations"

可用的 Filament Shield 命令

shield:doctor

  • 显示有关 Filament Shield 的有用信息。

shield:install

设置核心包要求并安装 Shield。接受以下标志:

  • --fresh 重新运行迁移
  • --only 仅设置 shield,不生成权限和创建超级管理员

shield:generate

为 Filament 实体生成权限和/或策略。接受以下标志:

  • --all 为所有实体生成权限/策略
  • --option[=OPTION] 覆盖配置生成器选项(policies_and_permissionspoliciespermissions
  • --resource[=RESOURCE] 一个或多个资源,用逗号(,)分隔
  • --page[=PAGE] 一个或多个页面,用逗号(,)分隔
  • --widget[=WIDGET] 一个或多个小部件,用逗号(,)分隔
  • --exclude 生成时排除指定的实体
  • --ignore-config-exclude 生成时忽略配置 exclude 选项
  • --ignore-existing-policies 不覆盖现有策略。

shield:super-admin

创建一个具有超级管理员角色的用户。

  • 接受一个 --user= 参数,该参数将使用提供的 ID 查找要成为超级管理员的用户。

shield:publish

  • 发布 Shield RoleResource 并按需进行自定义

shield:seeder

  • 通过设置您的角色和权限或添加您自己的种子来轻松部署

测试

composer test

变更日志

有关最近更改的更多信息,请参阅 变更日志

贡献

有关详细信息,请参阅 贡献指南

安全漏洞

请查看 我们的安全策略 了解如何报告安全漏洞。

鸣谢

许可协议

MIT 许可协议(MIT)。有关更多信息,请参阅 许可文件