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

时间:2020-08-28 13:27:54

标签: laravel policy

我有一个项目,希望由具有查看角色的特定用户查看特定页面,例如,我有一个具有管理员角色的用户1,而管理员角色具有查看该页面的能力。我的设计中,我制作了3个模型User,Roles和Abilities

用户模型:

<?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');
    }
}

索引函数应该是与function view中的UserPolicy相关的函数 这是位于我的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

在策略中,当我将其链接到已登录用户的角色名称时,一切正常,但如果我想将其链接到该角色的功能,则它不起作用,因此,关于{应该执行UserPolicy中的{1}}吗?

1 个答案:

答案 0 :(得分:1)

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

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

->exists()将查询转换为EXISTS查询,如果查询发现任何内容而不必返回任何行,则它将返回布尔值。

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');
}