如果用户属于许多组织,则单独的角色/权限
Posted
技术标签:
【中文标题】如果用户属于许多组织,则单独的角色/权限【英文标题】:Separate roles/permissions if user belongs to many organizations 【发布时间】:2019-06-24 14:45:23 【问题描述】:我有一个用户可以属于多个组织的应用程序。我想以一种用户可以对每个组织具有不同角色/权限的方式进行设置。我正在使用 Laravel 并计划实施 Spatie/laravel-permission。实现这一点的最佳方法是什么?
我尝试设置两个保护,一个用于主用户帐户,另一个用于用户和他们登录的组织之间的枢轴模型。所以基本上当他们使用主用户模型登录应用程序时,我会询问他们想登录哪个组织,当他们选择组织时,我还将在数据透视模型上设置一个身份验证会话,将用户链接到组织并访问该模型之外的角色。这可行,但必须管理身份验证会话有点痛苦。
// User Model
class User extends Authenticatable
public function organizationUsers()
return $this->hasMany(OrganizationUser::class);
// OrganizationUser Model
class Organziationuser extends Authenticatable
use HasRoles;
public $guard_name = 'organization_user';
public function organization()
return $this->belongsTo(Organization::class);
public function user()
return $this->belongsTo(User::class);
我希望用户能够使用单次登录来登录应用程序,但也能够对不同的组织拥有不同的权限。
【问题讨论】:
Spatie Laravel 权限做得很好,但不能响应所有用例。您应该考虑实施自己的角色/权限系统。一旦您深入了解并提供更多灵活性,这并不难。 我想知道在 model_has_roles 和 model_has_permissions 表中添加一个 organization_id 是否会是票。然后我应该能够过滤该 organization_id 以获取用户模型的角色和权限。嗯.. 你可以试试,但考虑一下:包的基础是分配角色/权限和检查角色/权限。通过添加一个 organization_id,您不能分配也不能检查包。你需要自己做。包中唯一留给您的是缓存和模型/迁移的基础。在我看来,不要过度依赖包是件好事。尤其是当它们没有达到预期的行为时。 【参考方案1】:我通过执行以下操作解决了这个问题。我欢迎大家对这种方法的看法提供反馈!
注意:目前我只使用具有 Spatie 权限的model_has_roles
表,并且始终使用$user->can('Permission')
来检查权限。
-
我们公司模型有如下关系和方法
class Company extends Model
public function owner(): HasOne
return $this->hasOne(User::class, 'id', 'user_id');
public function users(): BelongsToMany
return $this->belongsToMany(
User::class, 'company_users', 'company_id', 'user_id'
)->using(CompanyUser::class);
public function addTeamMember(User $user)
$this->users()->detach($user);
$this->users()->attach($user);
-
我们修改了枢轴模型以具有 Spatie
HasRoles
特征。这允许我们将角色分配给CompanyUser
,而不是 Auth 用户。您还需要指定默认的守卫或 Spatie 权限。
class CompanyUser extends Pivot
use HasRoles;
protected $guard_name = 'web';
-
在用户模型上,我创建了
HasCompanies
特征。这提供了关系并提供了一种将角色分配给新公司用户的方法。此外,它还覆盖了门 can()
方法。
用户可以属于多家公司,但一次只能拥有一家活跃的公司(即他们正在查看的公司)。我们使用current_company_id
列来定义它。
确保数据透视表 ID 被拉过也很重要(这不是标准的),因为这是我们现在在 Spatie model_has_roles table
中使用的。
trait HasCompanies
public function companies(): HasMany
return $this->hasMany(Company::class);
public function currentCompany(): HasOne
return $this->hasOne(Company::class, 'id', 'current_company_id');
public function teams(): BelongsToMany
return $this->belongsToMany(
Company::class, 'company_users', 'user_id', 'company_id'
)->using(CompanyUser::class)->withPivot('id');
public function switchCompanies(Company $company): void
$this->current_company_id = $company->id;
$this->save();
public function assignRolesForCompany(Company $company, ...$roles)
if($company = $this->teams()->where('companies.id', $company->id)->first())
/** @var CompanyUser $companyUser */
$companyUser = $company->pivot;
$companyUser->assignRole($roles);
return;
throw new Exception('Roles could not be assigned to company user');
public function can($ability, $arguments = [])
if(isset($this->current_company_id))
/** @var CompanyUser $companyUser */
$companyUser = $this->teams()->where('companies.id', $this->current_company_id)->first()->pivot;
if($companyUser->hasPermissionTo($ability))
return true;
// We still run through the gate on fail, as this will check for gate bypass. i.e. Super User
return app(Gate::class)->forUser($this)->check('InvalidPermission');
return app(Gate::class)->forUser($this)->check($ability, $arguments);
现在我们可以这样做了:
-
创建角色和权限
/** @var Role $ownerRoll */
$ownerRoll = Role::create(['name' => 'Owner']);
/** @var Permission $permission */
$permission = Permission::create([
'name' => 'Create Company',
'guard_name' => 'web',
]);
$ownerRoll->givePermissionTo($permission);
-
使用所有者用户创建一个新公司,然后将该公司切换到该所有者的活动公司。
public function store(CompanyStoreRequest $request)
DB::transaction(function () use($request)
/** @var User $owner */
$owner = User::findOrFail($request->user_id);
/** @var Company $company */
$company = $owner->companies()->create($request->validated());
$company->addTeamMember($owner);
$owner->assignRolesForCompany($company, 'Owner');
$owner->switchCompanies($company);
);
return redirect()->back();
所以这一切都有效,我主要担心的是:
我们正在覆盖 can 方法。可能还有其他未捕获的授权方法/门功能。
我们有 2 组 model_permissions。 Auth 用户和公司用户。我认为我需要进行一些检查,以确保只能将正确类型的用户分配给角色。在这个阶段,所有管理员用户都将拥有权限分配给他们的 auth 用户,而任何拥有公司的用户都应该只拥有公司用户模型的权限
【讨论】:
以上是关于如果用户属于许多组织,则单独的角色/权限的主要内容,如果未能解决你的问题,请参考以下文章