mcpField
L
laravel-permission-development

laravel-permission-development

github.com/spatie开发13.0k301 次安装6 天前更新
代码仓库

关于 laravel-permission-development

面向使用 spatie/laravel-permission 的 Laravel 开发者,提供角色、权限与访问控制的开发指导。内容涵盖权限检查、路由中间件、Blade 指令及多团队配置。

主要功能

  1. 01角色与权限的创建及分配
  2. 02使用 Gate 进行权限检查
  3. 03路由中间件与 Blade 指令
  4. 04团队、多租户权限配置
  5. 05权限缓存与 Seeder 管理

适用场景

  1. 01为用户分配角色并设置权限
  2. 02在路由和 Blade 中执行授权检查
  3. 03配置 Super Admin 与团队权限
  4. 04编写角色和权限的 Seeder

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/spatie/laravel-permission --skill laravel-permission-development

安装后在 Claude Code 中输入/laravel-permission-development确认已加载。

详细介绍

Laravel 权限开发

何时使用此技能

在使用 spatie/laravel-permission 处理授权、角色、权限、访问控制、中间件守卫或 Blade 权限指令时,使用此技能。

核心概念

  • 用户拥有角色,角色拥有权限,应用检查权限(而非角色)。
  • 直接为用户分配权限是一种反模式;应将权限分配给角色。
  • 所有授权检查都使用 $user->can('permission-name')(通过 Gate 支持超级管理员)。
  • User 模型会添加 HasRoles trait(其中包含 HasPermissions)。

设置

将 HasRoles trait 添加到 User 模型:

use Spatie\Permission\Traits\HasRoles;

class User extends Authenticatable
{
    use HasRoles;
}

创建角色和权限

use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;

$role = Role::create(['name' => 'writer']);
$permission = Permission::create(['name' => 'edit articles']);

// findOrCreate is idempotent (safe for seeders)
$role = Role::findOrCreate('writer', 'web');
$permission = Permission::findOrCreate('edit articles', 'web');

分配角色和权限

// Assign roles to users
$user->assignRole('writer');
$user->assignRole('writer', 'admin');
$user->assignRole(['writer', 'admin']);
$user->syncRoles(['writer', 'admin']); // replaces all
$user->removeRole('writer');

// Assign permissions to roles (preferred)
$role->givePermissionTo('edit articles');
$role->givePermissionTo(['edit articles', 'delete articles']);
$role->syncPermissions(['edit articles', 'delete articles']);
$role->revokePermissionTo('edit articles');

// Reverse assignment
$permission->assignRole('writer');
$permission->syncRoles(['writer', 'editor']);
$permission->removeRole('writer');

检查角色和权限

// Permission checks (preferred - supports Super Admin via Gate)
$user->can('edit articles');
$user->canAny(['edit articles', 'delete articles']);

// Direct package methods (bypass Gate, no Super Admin support)
$user->hasPermissionTo('edit articles');
$user->hasAnyPermission(['edit articles', 'publish articles']);
$user->hasAllPermissions(['edit articles', 'publish articles']);
$user->hasDirectPermission('edit articles');

// Role checks
$user->hasRole('writer');
$user->hasAnyRole(['writer', 'editor']);
$user->hasAllRoles(['writer', 'editor']);
$user->hasExactRoles(['writer', 'editor']);

// Get assigned roles and permissions
$user->getRoleNames();           // Collection of role name strings
$user->getPermissionNames();     // Collection of permission name strings
$user->getDirectPermissions();   // Direct permissions only
$user->getPermissionsViaRoles(); // Inherited via roles
$user->getAllPermissions();      // Both direct and inherited

查询作用域

$users = User::role('writer')->get();
$users = User::withoutRole('writer')->get();
$users = User::permission('edit articles')->get();
$users = User::withoutPermission('edit articles')->get();

中间件

在 bootstrap/app.php 中注册中间件别名:

->withMiddleware(function (Middleware $middleware) {
    $middleware->alias([
        'role' => \Spatie\Permission\Middleware\RoleMiddleware::class,
        'permission' => \Spatie\Permission\Middleware\PermissionMiddleware::class,
        'role_or_permission' => \Spatie\Permission\Middleware\RoleOrPermissionMiddleware::class,
    ]);
})

在路由中使用(用管道符 | 表示 OR 逻辑):

Route::middleware(['permission:edit articles'])->group(function () { ... });
Route::middleware(['role:manager|writer'])->group(function () { ... });
Route::middleware(['role_or_permission:manager|edit articles'])->group(function () { ... });

// With specific guard
Route::middleware(['role:manager,api'])->group(function () { ... });

对于单个权限,也可以使用 Laravel 内置的 can 中间件:

Route::middleware(['can:edit articles'])->group(function () { ... });

Blade 指令

优先使用 @can(基于权限),而非 @role(基于角色):

@can('edit articles')
    {{-- User can edit articles (supports Super Admin) --}}
@endcan

@canany(['edit articles', 'delete articles'])
    {{-- User can do at least one --}}
@endcanany

@role('admin')
    {{-- Only use for super-admin type checks --}}
@endrole

@hasanyrole('writer|admin')
    {{-- Has writer or admin --}}
@endhasanyrole

超级管理员

在 AppServiceProvider::boot() 中使用 Gate::before:

use Illuminate\Support\Facades\Gate;

public function boot(): void
{
    Gate::before(function ($user, $ability) {
        return $user->hasRole('Super Admin') ? true : null;
    });
}

这会使 $user->can() 和 @can 对超级管理员始终返回 true。必须返回 null(而非 false),以便对其他用户执行常规检查。

策略

在策略方法中使用 $user->can() 检查权限:

class PostPolicy
{
    public function update(User $user, Post $post): bool
    {
        if ($user->can('edit all posts')) {
            return true;
        }

        return $user->can('edit own posts') && $user->id === $post->user_id;
    }
}

枚举

enum RolesEnum: string
{
    case WRITER = 'writer';
    case EDITOR = 'editor';
}

enum PermissionsEnum: string
{
    case EDIT_POSTS = 'edit posts';
    case DELETE_POSTS = 'delete posts';
}

// Most methods accept enums directly
Permission::findOrCreate(PermissionsEnum::EDIT_POSTS, 'web');
$user->assignRole(RolesEnum::WRITER);
$user->hasRole(RolesEnum::WRITER);
$role->givePermissionTo(PermissionsEnum::EDIT_POSTS);
$user->hasPermissionTo(PermissionsEnum::EDIT_POSTS);

数据填充

填充数据时务必刷新权限缓存:

class RolesAndPermissionsSeeder extends Seeder
{
    public function run(): void
    {
        // Reset cache
        app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();

        // Create permissions
        Permission::findOrCreate('edit articles', 'web');
        Permission::findOrCreate('delete articles', 'web');

        // Create roles and assign permissions
        Role::findOrCreate('writer', 'web')
            ->givePermissionTo(['edit articles']);

        Role::findOrCreate('admin', 'web')
            ->givePermissionTo(Permission::all());
    }
}

Teams(多租户)

运行迁移前,在 config/permission.php 中启用:

'teams' => true,

在中间件中设置当前团队:

setPermissionsTeamId($teamId);

切换团队时,清除缓存的关联:

$user->unsetRelation('roles')->unsetRelation('permissions');

事件

在 config/permission.php 中启用:

'events_enabled' => true,

可用事件:命名空间 Spatie\Permission\Events 中的 RoleAttachedEvent、RoleDetachedEvent、PermissionAttachedEvent、PermissionDetachedEvent。

性能

  • 权限会自动缓存。通过软件包方法更改角色或权限时,会刷新缓存。
  • 直接执行数据库操作后,手动刷新缓存:app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions()
  • 批量填充数据时,可使用 Permission::insert() 提升速度,但之后要刷新缓存。

评论

支持 Markdown