Laravel 基于角色特定能力的角色和权限

Laravel Roles and Permissions based on Role specific Ability

我有一个项目,在这个项目中,我希望具有查看角色的特定用户可以查看特定页面,例如,我的用户 1 具有管理员角色,并且管理员角色能够查看此页面在我的设计页面中,我制作了 3 个模型用户、角色和能力

用户模型:

<?php
    
namespace App;
    
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
    
class User extends Authenticatable
{
    use Notifiable;
    
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password','district','area','committee','position',
    ];
    
    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];
    
    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];
    
    public function answer()
    {
        return $this->hasMany('App\Answer');
    }
    
    public function roles()
    {
        return $this->belongsToMany('App\Role');
    }
    
    public function hasRole($role)
    {
        if ($this->roles()->where('name', $role)->first()) {
            return true;
        }
    
        return false;
    }
    
    public function assignRole($role)
    {
        $this->roles()->save($role);
    }
}

榜样:

<?php
    
namespace App;
   
use Illuminate\Database\Eloquent\Model;
    
class Role extends Model
{
    protected $fillable = ['name'];
    
    public function abilities()
    {
        return $this->belongsToMany('App\Ability');
    }
    
    public function hasAbility($ability)
    {
        if ($this->abilities()->where('name', $ability)->first()) {
            return true;
        }
        
        return false;
    }
      
    public function assignAbility($ability)
    {
        $this->abilities()->save($ability);
    }
    
    public function users()
    {
        return $this->belongsToMany('App\User');
    }    
}

能力模型:

<?php
    
namespace App;
    
use Illuminate\Database\Eloquent\Model;
  
class Ability extends Model
{
    protected $fillable = ['name'];
    
    public function roles()
    {
        return $this->belongsToMany('App\Role');
    }
}

这是我的 UserPolicy:

<?php
    
namespace App\Policies;
    
use App\User;
use App\Role;
use Illuminate\Auth\Access\HandlesAuthorization;
    
class UserPolicy
{
    use HandlesAuthorization;
    
    public function view (Role $role)
    {
        return $role->hasAbility('view');
    }
    
    public function manage (User $user)
    {
        return true;
    }
    
    public function edit (User $user)
    {
        return true;
    }
    
    public function update (User $user)
    {
        return true;
    }
    
    public function add (User $user)
    {
        return true;
    }
}

以及政策的控制者

<?php
    
namespace App\Http\Controllers;
    
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
    
use App\User;
use App\Role;
    
class MemberController extends Controller
{
    public function index(Role $role)
    {
        $this->authorize('view', $role);
    
        return view ('members.create')->with('users', User::all());
    }
    
    public function manage(User $user)
    {
        $this->authorize('manage', $user);
        
        return view ('members.manage')->with('users', User::all());
    }
    
    public function edit(User $user)
    {
        $this->authorize('edit', $user);
    
        return view ('members.edit')->with('user', User::all())->with('roles', Role::all());
    }
    
    public function update(Request $request, User $user)
    {
        $this->authorize('update', $user);
    
        $user->roles()->sync($request->roles);
    
        return redirect('/members/edit');
    
    }
    
    public function store(User $user)
    {
        $this->authorize('add', $user);
        $this->validate(request(), [
            'name'      => ['required', 'string', 'max:255'],
            'district'  => ['required', 'string', 'max:255'],
            'area'      => ['required', 'string', 'max:255'],
            'committee' => ['required', 'string', 'max:255'],
            'position'  => ['required', 'string', 'max:255'],
            'email'     => ['required', 'string', 'email', 'max:255', 'unique:users'],
            'password'  => ['required', 'string', 'min:8', 'confirmed'],
        ]);
    
        $data = request()->all();
    
        $member = new User();
        $member->name      = $data['name'];
        $member->district  = $data['district'];
        $member->area      = $data['area'];
        $member->committee = $data['committee'];
        $member->position  = $data['position'];
        $member->email     = $data['email'];
        $member->password  = Hash::make($data['password']);
        
        $member->save();
    
        return redirect('/members/create');
    }
}

索引函数应该是UserPolicy中与function view相关的函数 这是位于我的 blade.php 文件

中的 can
@can('view', \App\Role::class)
    <li class="">
        <a class="" href="/members/create">
            <span><i class="fa fa-user-plus" aria-hidden="true"></i></span>
            <span>Add Member</span>
        </a>
    </li>
@endcan

在策略中,当我 link 将其设置为已登录用户角色的名称时,一切正常,但如果我想将其 link 设置为角色的能力,则它不会无法正常工作,所以知道应该如何实施 UserPolicy 中的 View Function 吗?

传递给策略的第一个参数是经过身份验证的 User,而不是它的 Role。我认为这行不通。也许如果您使用 EXISTS 查询重新实现。

public function view (User $user)
{
    return $user->roles()->whereHas('abilities', function ($ability) {
        $ability->where('name', 'view');
    })
    ->exists();
}

->exists() 将查询转换为 EXISTS 查询,如果查询找到任何内容而无需 return 任何行,它将 return 一个布尔值。

https://laravel.com/docs/7.x/queries#aggregates

您可以将该逻辑放入 User 方法中。

# User model
public function hasAbility($ability): bool
{
    return $this->roles()->whereHas('abilities', function ($ability) {
        $ability->where('name', 'view');
    })
    ->exists();
}
public function view (User $user)
{
    return $user->hasAbility('view');
}