2025-04-09 16:37:18 / 23
一、描述
将用户与角色和权限关联,允许您管理数据库中的用户权限和角色。
官方文档:https://spatie.be/docs/laravel-permission/v6/introduction
Packagist:https://packagist.org/packages/spatie/laravel-permission
安装:https://spatie.be/docs/laravel-permission/v6/installation-laravel
二、特殊介绍
在说明中,你将看到必须将特征添加到用户模型中才能启用此包的功能。InstallationHasRoles
因此,典型的基本用户模型将具有以下基本最低要求:
use Illuminate\\Foundation\\Auth\\User as Authenticatable;
use Spatie\\Permission\\Traits\\HasRoles;
class User extends Authenticatable
{
use HasRoles;
// ...
}
您的模型/对象不得具有 or 属性(或数据库中具有该名称的字段),也不得具有方法。这些将干扰此包提供的特征添加的属性和方法,从而在使用此包的方法检查角色和权限时导致意外结果。Userrolerolesroles()HasRoles
您的模型/对象不得具有 or 属性(或数据库中具有该名称的字段),也不得具有方法。这些将干扰此包(通过该特性调用)提供的特性所添加的属性和方法。Userpermissionpermissionspermissions()HasPermissionsHasRoles
三、迁移
如果是 mysql 5.7 需要修改 (125 改为 100)
$table->string('name', 100); // For MySQL 8.0 use string('name', 125);
$table->string('guard_name', 100); // For MySQL 8.0 use string('guard_name', 125);
然后执行
php artisan migrate
四、基本使用
1. 创建权限
use Spatie\\\\Permission\\\\Models\\\\Role;
use Spatie\\\\Permission\\\\Models\\\\Permission;
$role = Role::create(['name' => 'writer']);
$permission = Permission::create(['name' => 'edit articles']);
如果是 Teams
// with null team_id it creates a global role; global roles can be assigned to any team and they are unique
Role::create(['name' => 'writer', 'team_id' => null]);
// creates a role with team_id = 1; team roles can have the same name on different teams
Role::create(['name' => 'reader', 'team_id' => 1]);
// creating a role without team_id makes the role take the default global team_id
Role::create(['name' => 'reviewer']);
2. 为角色分配权限
可以使用以下任一方法为角色分配权限:
$role->givePermissionTo($permission);
$permission->assignRole($role);
3. 将权限同步到角色
可以使用以下任一方法为角色分配权限:
$role->syncPermissions($permissions);
$permission->syncRoles($roles);
4. 从角色中删除权限
可以使用以下任一方法为角色分配权限:
$role->revokePermissionTo($permission);
$permission->removeRole($role);
5. Guard Name - 待研究
6. 获取用户的权限
该特征将 Eloquent 关系添加到模型中,可以直接访问或用作基本查询:HasRoles
// get a list of all permissions directly assigned to the user
$permissionNames = $user->getPermissionNames(); // collection of name strings
$permissions = $user->permissions; // collection of permission objects
// get all permissions for the user, either directly, or from roles, or from both
$permissions = $user->getDirectPermissions();
$permissions = $user->getPermissionsViaRoles();
$permissions = $user->getAllPermissions();
// get the names of the user's roles
$roles = $user->getRoleNames(); // Returns a collection
7. 范围
该特征还会向模型添加和限定范围,以将查询范围限定为某些角色或权限:HasRolesrolewithoutRole
$users = User::role('writer')->get(); // Returns only users with the role 'writer'
$nonEditors = User::withoutRole('editor')->get(); // Returns only users without the role 'editor'
和 作用域可以接受字符串、对象或对象。rolewithoutRole\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Spatie\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Permission\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Models\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Role\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Illuminate\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Support\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Collection
相同的特征还增加了范围,以仅获取具有或没有特定权限的用户。
$users = User::permission('edit articles')->get(); // Returns only users with the permission 'edit articles' (inherited or directly)
$usersWhoCannotEditArticles = User::withoutPermission('edit articles')->get(); // Returns all users without the permission 'edit articles' (inherited or directly)
范围可以接受字符串、对象或对象。\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Spatie\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Permission\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Models\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Permission\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Illuminate\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Support\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Collection
8. Eloquent Calls
由于角色和权限模型是从 Eloquent 模型扩展而来的,因此也可以使用基本的 Eloquent 调用:
$all_users_with_all_their_roles = User::with('roles')->get();
$all_users_with_all_their_direct_permissions = User::with('permissions')->get();
$all_roles_in_database = Role::all()->pluck('name');
$users_without_any_roles = User::doesntHave('roles')->get();
$all_roles_except_a_and_b = Role::whereNotIn('name', ['role A', 'role B'])->get();
9. 计算具有角色的用户数
计算具有特定角色的所有用户的一种方法是使用其角色筛选所有用户的集合:
$superAdminCount = User::with('roles')->get()->filter(
fn ($user) => $user->roles->where('name', 'Super Admin')->toArray()
)->count();
五、直接权限
1. 最佳实践
最好将权限分配给“角色”,然后再将“角色”分配给“用户”。
请参阅角色与权限部分的文档部分,以获得更深入的解释。
但是,如果您有理由直接将个人权限分配给特定用户(而不是分配给这些用户的角色),则可以按如下所述执行此操作:
2. 对用户的直接权限
可以向任何用户授予权限:
$user->givePermissionTo('edit articles');
// You can also give multiple permission at once
$user->givePermissionTo('edit articles', 'delete articles');
// You may also pass an array
$user->givePermissionTo(['edit articles', 'delete articles']);
可以撤消用户的权限:
$user->revokePermissionTo('edit articles');
或者一次性撤销和添加新权限:
$user->syncPermissions(['edit articles', 'delete articles']);
您可以检查用户是否具有权限:
$user->hasPermissionTo('edit articles');
或者,您可以传递一个表示权限 ID 的整数
$user->hasPermissionTo('1');
$user->hasPermissionTo(Permission::find(1)->id);
$user->hasPermissionTo($somePermission->id);
您可以检查用户是否具有以下权限数组中的任何一个:
$user->hasAnyPermission(['edit articles', 'publish articles', 'unpublish articles']);
...或者,如果用户具有“所有”权限数组:
$user->hasAllPermissions(['edit articles', 'publish articles', 'unpublish articles']);
您也可以将整数传递给按权限 ID 查找
$user->hasAnyPermission(['edit articles', 1, 5]);
与通过角色分配的所有权限一样,您可以使用 Laravel 的默认函数检查用户是否具有权限:can
$user->can('edit articles');
六、通过角色使用权限
1. 分配角色
可以将角色分配给任何用户:
$user->assignRole('writer');
// You can also assign multiple roles at once
$user->assignRole('writer', 'admin');
// or as an array
$user->assignRole(['writer', 'admin']);
可以从用户中删除角色:
$user->removeRole('writer');
还可以同步角色:
// All current roles will be removed from the user and replaced by the array given
$user->syncRoles(['writer', 'admin']);
2. 检查角色
您可以确定用户是否具有特定角色:
$user->hasRole('writer');
// or at least one role from an array of roles:
$user->hasRole(['editor', 'moderator']);
您还可以确定用户是否具有任何给定的角色列表:
$user->hasAnyRole(['writer', 'reader']);
// or
$user->hasAnyRole('writer', 'reader');
您还可以确定用户是否具有所有给定的角色列表:
$user->hasAllRoles(Role::all());
您还可以确定用户是否完全具有所有给定的角色列表:
$user->hasExactRoles(Role::all());
和 函数可以接受 字符串、对象或对象。
assignRolehasRolehasAnyRolehasAllRoleshasExactRolesremoveRole\\\\\\\\\\\\\\\\Spatie\\\\\\\\\\\\\\\\Permission\\\\\\\\\\\\\\\\Models\\\\\\\\\\\\\\\\Role\\\\\\\\\\\\\\\\Illuminate\\\\\\\\\\\\\\\\Support\\\\\\\\\\\\\\\\Collection
3. 为角色分配权限
可以向角色授予权限:
$role->givePermissionTo('edit articles');
您可以确定角色是否具有特定权限:
$role->hasPermissionTo('edit articles');
可以从角色中撤消权限:
$role->revokePermissionTo('edit articles');
或者一次性撤销和添加新权限:
$role->syncPermissions(['edit articles', 'delete articles']);
函数可以接受 字符串或对象。givePermissionTorevokePermissionToSpatie\\\\\\\\Permission\\\\\\\\Models\\\\\\\\Permission
注意:权限会自动从角色继承。
4. 角色具有哪些权限?
任何给定角色的属性都会返回一个包含所有相关权限对象的集合。此集合可以响应通常的 Eloquent Collection 操作,例如计数、排序等。permissions
// get collection
$role->permissions;
// return only the permission names:
$role->permissions->pluck('name');
// count the number of permissions assigned to a role
count($role->permissions);
// or
$role->permissions->count();
5. 向用户分配直接权限
此外,还可以为用户分配个人权限。 例如:
$role = Role::findByName('writer');
$role->givePermissionTo('edit articles');
$user->assignRole('writer');
$user->givePermissionTo('delete articles');
在上面的示例中,角色被授予编辑文章的权限,并将此角色分配给用户。 现在,用户可以编辑文章并另外删除文章。“删除文章”的权限是用户的直接权限,因为它是直接分配给他们的。 当我们调用它时返回 , 但对于.$user->hasDirectPermission('delete articles')truefalse$user->hasDirectPermission('edit articles')
如果构建用于设置应用程序中角色和用户权限的表单,并且想要限制或更改用户角色的继承权限,即仅允许更改用户的直接权限,则此方法非常有用。
您可以检查用户是否具有直接分配的一组权限中的“特定”或“全部”或“任意”权限:
// Check if the user has Direct permission
$user->hasDirectPermission('edit articles')
// Check if the user has All direct permissions
$user->hasAllDirectPermissions(['edit articles', 'delete articles']);
// Check if the user has Any permission directly
$user->hasAnyDirectPermission(['create articles', 'delete articles']);
按照前面的例子,当我们调用它时,返回 ,因为用户没有作为直接权限。 当我们调用 时,它会返回,因为用户具有提供的权限之一。$user->hasAllDirectPermissions(['edit articles', 'delete articles'])falseedit articles$user->hasAnyDirectPermission('edit articles')true
您可以检查所有这些权限:
// Direct permissions
$user->getDirectPermissions() // Or $user->permissions;
// Permissions inherited from the user's roles
$user->getPermissionsViaRoles();
// All permissions which apply on the user (inherited and direct)
$user->getAllPermissions();
所有这些响应都是对象的集合。Spatie\\\\\\\\Permission\\\\\\\\Models\\\\\\\\Permission
如果我们遵循前面的示例,第一个响应将是具有权限和 第二个将是具有权限的集合,第三个将包含两者。delete articleedit article
七、枚举
待研究
八、Teams 权限
启用后,teams 权限可为各种方案提供灵活的控制
1. 使用 Teams 权限
在实施用于在身份验证过程中选择团队的解决方案后 (例如,将当前选定团队的team_id会期: ), 我们可以从任何地方设置全局,但如果您创建一个 .session(['team_id' => $team->team_id]);team_idMiddleware
团队中间件示例:
namespace App\\\\Http\\\\Middleware;
class TeamsPermission
{
public function handle($request, \\\\Closure $next){
if(!empty(auth()->user())){
// session value set on login
setPermissionsTeamId(session('team_id'));
}
// other custom ways to get team_id
/*if(!empty(auth('api')->user())){
// `getTeamIdFromToken()` example of custom method for getting the set team_id
setPermissionsTeamId(auth('api')->user()->getTeamIdFromToken());
}*/
return $next($request);
}
}
您还必须设置数组$middlewarePriority 在中间件之前包含您的自定义中间件,
否则您可能会得到app/Http/Kernel.phpSubstituteBindings404 未找到响应时403 未授权可能会收到响应。
2. 角色创建
创建角色时,可以将 作为可选参数传递team_id
// with null team_id it creates a global role; global roles can be assigned to any team and they are unique
Role::create(['name' => 'writer', 'team_id' => null]);
// creates a role with team_id = 1; team roles can have the same name on different teams
Role::create(['name' => 'reader', 'team_id' => 1]);
// creating a role without team_id makes the role take the default global team_id
Role::create(['name' => 'reviewer']);
3. 角色/权限分配和删除
团队的角色/权限分配和删除与没有团队相同,但它们采用登录时设置的全局。team_id
4. 更改活动团队 ID
虽然您的中间件将在登录时设置用户的中间件,但出于各种原因,您以后可能需要将其设置为另一个团队。最常见的两个原因是:team_id
5. 登录后切换团队
如果应用程序允许用户在他们所属的各种团队之间切换,则可以通过调用和取消设置关系来激活该团队的角色/权限,如下所述。setPermissionsTeamId($new_team_id)
6. 管理团队详细信息
您可能已创建用户管理器页面,您可以在其中查看某些团队中用户的角色/权限。若要管理该用户所属的每个团队中的该用户,还必须使用使查找与该新团队相关,并取消设置先前关系,如下所述。setPermissionsTeamId($new_team_id)
7. 查询其他团队的角色/权限
每当您切换活动使用 时,您需要在查询该用户具有哪些角色/权限(等)之前以及调用任何授权函数(、、等)之前查看用户/模型的和关系。team_idsetPermissionsTeamId()unsetrolespermissions$user->rolescan()hasPermissionTo()hasRole()
例:
// set active global team_id
setPermissionsTeamId($new_team_id);
// $user = Auth::user();
// unset cached model relations so new team relations will get reloaded
$user->unsetRelation('roles')->unsetRelation('permissions');
// Now you can check:
$roles = $user->roles;
$hasRole = $user->hasRole('my_role');
$user->hasPermissionTo('foo');
$user->can('bar');
// etc
8. 在 Teams 上定义超级管理员
全局角色可以分配给不同的团队,并且(这是关系的主键)始终是必需的。team_id
如果要为用户提供“超级管理员”全局角色,则在创建新团队时,必须将其分配给用户。例:
namespace App\\\\Models;
class YourTeamModel extends \\\\Illuminate\\\\Database\\\\Eloquent\\\\Model
{
// ...
public static function boot()
{
parent::boot();
// here assign this team to a global user with global default role
self::created(function ($model) {
// temporary: get session team_id for restore at end
$session_team_id = getPermissionsTeamId();
// set actual new team_id to package instance
setPermissionsTeamId($model);
// get the admin user and assign roles/permissions on new team model
User::find('your_user_id')->assignRole('Super Admin');
// restore session team_id to package instance using temporary value stored above
setPermissionsTeamId($session_team_id);
});
}
// ...
}