laravel-permission-development
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseLaravel Permission Development
Laravel Permission 开发指南
When to use this skill
何时使用该技能
Use this skill when working with authorization, roles, permissions, access control, middleware guards, or Blade permission directives using spatie/laravel-permission.
当你使用spatie/laravel-permission处理授权、角色、权限、访问控制、中间件守卫或Blade权限指令时,可以使用本技能。
Core Concepts
核心概念
- Users have Roles, Roles have Permissions, Apps check Permissions (not Roles).
- Direct permissions on users are an anti-pattern; assign permissions to roles instead.
- Use for all authorization checks (supports Super Admin via Gate).
$user->can('permission-name') - The trait (which includes
HasRoles) is added to User models.HasPermissions
- 用户拥有角色,角色拥有权限,应用校验权限(而非角色)。
- 直接给用户分配权限是反模式;应改为将权限分配给角色。
- 所有授权校验都使用(通过Gate支持超级管理员)。
$user->can('permission-name') - 需将trait(包含
HasRoles)添加到User模型中。HasPermissions
Setup
配置步骤
Add the trait to your User model:
HasRolesphp
use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable
{
use HasRoles;
}将 trait添加到你的User模型中:
HasRolesphp
use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable
{
use HasRoles;
}Creating Roles and Permissions
创建角色与权限
php
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');php
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;
$role = Role::create(['name' => 'writer']);
$permission = Permission::create(['name' => 'edit articles']);
// findOrCreate是幂等方法(适用于数据填充)
$role = Role::findOrCreate('writer', 'web');
$permission = Permission::findOrCreate('edit articles', 'web');Assigning Roles and Permissions
分配角色与权限
php
// 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');php
// 给用户分配角色
$user->assignRole('writer');
$user->assignRole('writer', 'admin');
$user->assignRole(['writer', 'admin']);
$user->syncRoles(['writer', 'admin']); // 替换所有现有角色
$user->removeRole('writer');
// 给角色分配权限(推荐方式)
$role->givePermissionTo('edit articles');
$role->givePermissionTo(['edit articles', 'delete articles']);
$role->syncPermissions(['edit articles', 'delete articles']);
$role->revokePermissionTo('edit articles');
// 反向分配
$permission->assignRole('writer');
$permission->syncRoles(['writer', 'editor']);
$permission->removeRole('writer');Checking Roles and Permissions
校验角色与权限
php
// 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 inheritedphp
// 权限校验(推荐方式 - 通过Gate支持超级管理员)
$user->can('edit articles');
$user->canAny(['edit articles', 'delete articles']);
// 直接调用包方法(绕过Gate,不支持超级管理员)
$user->hasPermissionTo('edit articles');
$user->hasAnyPermission(['edit articles', 'publish articles']);
$user->hasAllPermissions(['edit articles', 'publish articles']);
$user->hasDirectPermission('edit articles');
// 角色校验
$user->hasRole('writer');
$user->hasAnyRole(['writer', 'editor']);
$user->hasAllRoles(['writer', 'editor']);
$user->hasExactRoles(['writer', 'editor']);
// 获取已分配的角色与权限
$user->getRoleNames(); // 角色名称集合
$user->getPermissionNames(); // 权限名称集合
$user->getDirectPermissions(); // 仅直接分配的权限
$user->getPermissionsViaRoles(); // 通过角色继承的权限
$user->getAllPermissions(); // 直接分配与继承的所有权限Query Scopes
查询作用域
php
$users = User::role('writer')->get();
$users = User::withoutRole('writer')->get();
$users = User::permission('edit articles')->get();
$users = User::withoutPermission('edit articles')->get();php
$users = User::role('writer')->get();
$users = User::withoutRole('writer')->get();
$users = User::permission('edit articles')->get();
$users = User::withoutPermission('edit articles')->get();Middleware
中间件
Register middleware aliases in :
bootstrap/app.phpphp
->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,
]);
})Use in routes (pipe for OR logic):
|php
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 () { ... });For single permissions, Laravel's built-in middleware also works:
canphp
Route::middleware(['can:edit articles'])->group(function () { ... });在中注册中间件别名:
bootstrap/app.phpphp
->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,
]);
})在路由中使用(使用竖线表示或逻辑):
|php
Route::middleware(['permission:edit articles'])->group(function () { ... });
Route::middleware(['role:manager|writer'])->group(function () { ... });
Route::middleware(['role_or_permission:manager|edit articles'])->group(function () { ... });
// 指定守卫
Route::middleware(['role:manager,api'])->group(function () { ... });对于单个权限,Laravel内置的中间件同样适用:
canphp
Route::middleware(['can:edit articles'])->group(function () { ... });Blade Directives
Blade指令
Prefer (permission-based) over (role-based):
@can@roleblade
@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优先使用(基于权限)而非(基于角色):
@can@roleblade
@can('edit articles')
{{-- 用户可编辑文章(支持超级管理员) --}}
@endcan
@canany(['edit articles', 'delete articles'])
{{-- 用户至少拥有其中一项权限 --}}
@endcanany
@role('admin')
{{-- 仅用于超级管理员类型的校验 --}}
@endrole
@hasanyrole('writer|admin')
{{-- 拥有writer或admin角色 --}}
@endhasanyroleSuper Admin
超级管理员
Use in :
Gate::beforeAppServiceProvider::boot()php
use Illuminate\Support\Facades\Gate;
public function boot(): void
{
Gate::before(function ($user, $ability) {
return $user->hasRole('Super Admin') ? true : null;
});
}This makes and always return true for Super Admins. Must return (not ) to allow normal checks for other users.
$user->can()@cannullfalse在中使用:
AppServiceProvider::boot()Gate::beforephp
use Illuminate\Support\Facades\Gate;
public function boot(): void
{
Gate::before(function ($user, $ability) {
return $user->hasRole('Super Admin') ? true : null;
});
}这会让超级管理员的和始终返回true。对于其他用户,必须返回(而非)以允许正常校验。
$user->can()@cannullfalsePolicies
策略
Use inside policy methods to check permissions:
$user->can()php
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;
}
}在策略方法中使用来校验权限:
$user->can()php
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;
}
}Enums
枚举
php
enum RolesEnum: string
{
case WRITER = 'writer';
case EDITOR = 'editor';
}
enum PermissionsEnum: string
{
case EDIT_POSTS = 'edit posts';
case DELETE_POSTS = 'delete posts';
}
// Creation requires ->value
Permission::findOrCreate(PermissionsEnum::EDIT_POSTS->value, 'web');
// Most methods accept enums directly
$user->assignRole(RolesEnum::WRITER);
$user->hasRole(RolesEnum::WRITER);
$role->givePermissionTo(PermissionsEnum::EDIT_POSTS);
$user->hasPermissionTo(PermissionsEnum::EDIT_POSTS);php
enum RolesEnum: string
{
case WRITER = 'writer';
case EDITOR = 'editor';
}
enum PermissionsEnum: string
{
case EDIT_POSTS = 'edit posts';
case DELETE_POSTS = 'delete posts';
}
// 创建时需使用->value
Permission::findOrCreate(PermissionsEnum::EDIT_POSTS->value, 'web');
// 大多数方法直接支持枚举
$user->assignRole(RolesEnum::WRITER);
$user->hasRole(RolesEnum::WRITER);
$role->givePermissionTo(PermissionsEnum::EDIT_POSTS);
$user->hasPermissionTo(PermissionsEnum::EDIT_POSTS);Seeding
数据填充
Always flush the permission cache when seeding:
php
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());
}
}数据填充时务必刷新权限缓存:
php
class RolesAndPermissionsSeeder extends Seeder
{
public function run(): void
{
// 重置缓存
app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();
// 创建权限
Permission::findOrCreate('edit articles', 'web');
Permission::findOrCreate('delete articles', 'web');
// 创建角色并分配权限
Role::findOrCreate('writer', 'web')
->givePermissionTo(['edit articles']);
Role::findOrCreate('admin', 'web')
->givePermissionTo(Permission::all());
}
}Teams (Multi-Tenancy)
团队(多租户)
Enable in before running migrations:
config/permission.phpphp
'teams' => true,Set the active team in middleware:
php
setPermissionsTeamId($teamId);When switching teams, unset cached relations:
php
$user->unsetRelation('roles')->unsetRelation('permissions');在运行迁移前,在中启用:
config/permission.phpphp
'teams' => true,在中间件中设置当前活跃团队:
php
setPermissionsTeamId($teamId);切换团队时,需清除缓存的关联关系:
php
$user->unsetRelation('roles')->unsetRelation('permissions');Events
事件
Enable in :
config/permission.phpphp
'events_enabled' => true,Available events: , , , in the namespace.
RoleAttachedEventRoleDetachedEventPermissionAttachedEventPermissionDetachedEventSpatie\Permission\Events在中启用:
config/permission.phpphp
'events_enabled' => true,可用事件:命名空间下的、、、。
Spatie\Permission\EventsRoleAttachedEventRoleDetachedEventPermissionAttachedEventPermissionDetachedEventPerformance
性能优化
- Permissions are cached automatically. The cache is flushed when roles/permissions change via package methods.
- After direct DB operations, flush manually:
app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions() - For bulk seeding, use for speed, but flush the cache afterward.
Permission::insert()
- 权限会自动缓存。当通过包方法修改角色/权限时,缓存会自动刷新。
- 直接操作数据库后,需手动刷新缓存:
app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions() - 批量填充数据时,使用提升速度,但之后需刷新缓存。
Permission::insert()