我有以下政策来确定用户是否能够查看合同。
public function view(User $user, Contract $contract)
{
if ($user->user_type->id == 2) { // If user is a vecino
if ($user->id == $contract->customer_id) {
return true;
}
} else if ($user->user_type->is_admin == true) { // If user is an admin
return true;
}
return false;
}
然后使用哪个检查授权
$this->authorize('view', $contract);
如何检查列表/数组/集合的授权?就像我通过Contract::all()
我还没有找到任何方法来做到这一点。我可以做一个循环,每次迭代都调用$ this-> authorize来检查授权,但这可能会影响性能。
有更好的方法吗?
答案 0 :(得分:1)
在这种情况下,我经常看到的设计是不检查所有合同(如果用户有权使用)。
您通常会在查询中过滤掉合同,而不是过滤掉带有策略的合同(通常在我从事过的项目中看到)。这主要是因为如果要进行分页,则要在执行查询之前进行所有过滤,以避免产生奇怪的分页数据,如果您删除了一半的合同(例如,带有策略的合同),则分页数据将不一致。
可以执行以下查询子句。
Contract::where('user_id', $user->id)->get();
我通常为了使自己更容易实现的一种版本是在用户模型中创建范围。
public function scopeOwned($query, User $user)
{
return $this->query->where('user_id', $user->id);
}
Contract::owned($user)->get();
答案 1 :(得分:1)
我目前使用的一个解决方案是混合方法,您可以在一个范围内定义规则,然后从允许您重用授权逻辑的策略中引用该范围。
// Contract model
public function scopeViewable($query)
{
// If the user is admin, just return the query unfiltered.
if (Auth::user()->user_type->is_admin) {
return $query;
}
// Check the contract belongs to the logged in user.
return $query->where('customer_id', Auth::id());
}
然后在您的政策中,引用该范围,但将其限制为当前模型。确保使用 exists()
返回布尔值。这实质上是检查您的模型是否可见。
// Contract Policy
public function view(User $user, Contract $contract)
{
return Contract::viewable()
->where('id', $contract->id)
->exists()
;
}
重要的是,您应该在检索模型集合时使用 范围,而不是为集合中的每个模型运行范围查询的策略。策略应用于单个模型实例。
Contract::viewable()->paginate(10);
// Or
Contract::viewable()->get();
但是,当您想查看单个合同时,您可以直接使用您的保单。
$this->authorize('view', $contract);
// Or
Auth::user()->can('view', [Contract::class, $contract]);
答案 2 :(得分:0)
您必须循环播放,一种循环到另一种循环。在控制器中或在策略上循环Contract
对象之间没有什么区别,但是通过制定策略来检查单个资源,因此我将在控制器中执行此操作。