bezhansalleh/filament-shield

Filament对`spatie/laravel-permission`的文件支持。

资助包维护!
bezhanSalleh

安装次数: 626 230

依赖关系: 42

建议者: 0

安全: 0

星星: 1 463

关注者: 18

分支: 173

开放问题: 0


README

filament-shield-art

FILAMENT 8.x Packagist Tests Passing Code Style Passing Downloads

护盾

为您的Filament Admin添加访问管理的最简单、最直观的方式

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

注意

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

重要

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

安装

  1. 通过composer安装包
composer require bezhansalleh/filament-shield
  1. Spatie\Permission\Traits\HasRoles特性添加到您的User模型
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. 现在运行以下命令以安装护盾
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;
    ...
}

策略

角色策略

使用 Laravel 10

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

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

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

//AppServiceProvider.php
use Illuminate\Support\Facades\Gate;
...
public function boot(): void
    {
        ...
        Gate::policy(\Spatie\Permission\Models\Role::class, \App\Policies\RolePolicy::class);
    }
...

无论您的 Laravel 版本如何,如果您已在 config 中启用,则可以跳过此步骤。

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

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

策略路径

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

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

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

Shield 还为具有自定义文件夹结构的第三方插件和 Models 生成策略和权限,要执行生成的策略,您需要将它们注册。

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

    ];
使用 Laravel 11
//AppServiceProvider.php
use Illuminate\Support\Facades\Gate;
...
class AppServiceProvider extends ServiceProvider
{
    ...
   public function boot(): void
    {
        ...
        Gate::policy(\App\Models\Blog\Author::class, \App\Policies\Blog\AuthorPolicy::class);
        Gate::policy(\Ramnzys\FilamentEmailLog\Models\Email::class, \App\Policies\EmailPolicy::class);
    }

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

盾牌组件默认不提供分配用户角色的功能,但是您可以使用 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)。有关更多信息,请参阅 许可文件