Php Spatial用户权限-属于许多公司,解决方案反馈

Php Spatial用户权限-属于许多公司,解决方案反馈,php,laravel,permissions,spatie,Php,Laravel,Permissions,Spatie,我遇到的情况是,一个用户可以属于多个团队/公司,并且在该团队/公司中,他们可以拥有不同的角色和权限,具体取决于他们登录到哪个团队/公司。我已经想出了以下解决方案,并希望得到一些反馈 注意:目前我仅使用具有空间权限的model\u has\u roles表,并始终使用$user->can('Permission')检查权限 我们的公司模式具有以下关系和方法 我们修改了pivot模型,使其具有SpatieHasRoles特性。这允许我们将角色分配给公司用户,而不是身份验证用户。您还需要指定默认的保护

我遇到的情况是,一个用户可以属于多个团队/公司,并且在该团队/公司中,他们可以拥有不同的角色和权限,具体取决于他们登录到哪个团队/公司。我已经想出了以下解决方案,并希望得到一些反馈

注意:目前我仅使用具有空间权限的
model\u has\u roles
表,并始终使用
$user->can('Permission')
检查权限

  • 我们的公司模式具有以下关系和方法
  • 我们修改了pivot模型,使其具有Spatie
    HasRoles
    特性。这允许我们将角色分配给
    公司用户
    ,而不是身份验证用户。您还需要指定默认的保护或空间权限
  • 在用户模型上,我创建了hascompanys特性。这提供了关系,并提供了将角色分配给新公司用户的方法。此外,它还会覆盖gate
    can()
    方法
  • 一个用户可以属于多个公司,但一次只能有一个活动公司(即他们正在查看的公司)。我们用
    当前公司id
    列定义它

    同样重要的是确保透视表ID被拉过(它将不是标准的),因为这是我们现在在Spatiale
    模型中使用的

    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();
        }
    
        private function companyWithPivot(Company $company)
        {
            return $this->teams()->where('companies.id', $company->id)->first();
        }
    
        public function assignRolesForCompany(Company $company, ...$roles)
        {
            if($company = $this->companyWithPivot($company)){
                /** @var CompanyUser $companyUser */
                $companyUser = $company->pivot;
                $companyUser->assignRole($roles);
                return;
            }
    
            throw new Exception('Roles could not be assigned to company user');
        }
    
        public function hasRoleForCurrentCompany(string $roles, Company $company = null, string $guard = null): bool
        {
            if(! $company){
                if(! $company = $this->currentCompany){
                    throw new Exception('Cannot check role for current company because it has not been set');
                }
            }
    
            if($company = $this->companyWithPivot($company)){
                /** @var CompanyUser $companyUser */
                $companyUser = $company->pivot;
                return $companyUser->hasRole($roles, $guard);
            }
    
            return false;
        }
    
        public function can($ability, $arguments = []): bool
        {
            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;
                }
    
                // Still run through the gate as this will check for gate bypass
                return app(Gate::class)->forUser($this)->check('N/A', []);
            }
    
            return app(Gate::class)->forUser($this)->check($ability, $arguments);
        }
    }
    
    现在我们可以这样做:

  • 创建角色和权限
  • 创建一个拥有用户的新公司,然后将此公司切换到该所有者的活动公司
  • 这一切都是可行的,我主要关心的是:

  • 我们正在覆盖can方法。可能还有其他未捕获的授权方法/门函数

  • 我们有两套model_权限。身份验证用户和公司用户。我认为我需要进行一些检查,以确保只能将正确类型的用户分配给角色。在此阶段,所有管理员用户都将拥有分配给其身份验证用户的权限,而拥有公司的任何用户都只应拥有公司用户模型的权限

  • class CompanyUser extends Pivot
    {
        use HasRoles;
    
        protected $guard_name = 'web';
    }
    
    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();
        }
    
        private function companyWithPivot(Company $company)
        {
            return $this->teams()->where('companies.id', $company->id)->first();
        }
    
        public function assignRolesForCompany(Company $company, ...$roles)
        {
            if($company = $this->companyWithPivot($company)){
                /** @var CompanyUser $companyUser */
                $companyUser = $company->pivot;
                $companyUser->assignRole($roles);
                return;
            }
    
            throw new Exception('Roles could not be assigned to company user');
        }
    
        public function hasRoleForCurrentCompany(string $roles, Company $company = null, string $guard = null): bool
        {
            if(! $company){
                if(! $company = $this->currentCompany){
                    throw new Exception('Cannot check role for current company because it has not been set');
                }
            }
    
            if($company = $this->companyWithPivot($company)){
                /** @var CompanyUser $companyUser */
                $companyUser = $company->pivot;
                return $companyUser->hasRole($roles, $guard);
            }
    
            return false;
        }
    
        public function can($ability, $arguments = []): bool
        {
            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;
                }
    
                // Still run through the gate as this will check for gate bypass
                return app(Gate::class)->forUser($this)->check('N/A', []);
            }
    
            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();
    }