如何在Laravel中为列表或数组定义策略?

时间:2019-05-16 10:36:36

标签: laravel permissions authorization roles laravel-passport

我有以下政策来确定用户是否能够查看合同。

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来检查授权,但这可能会影响性能。

有更好的方法吗?

3 个答案:

答案 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对象之间没有什么区别,但是通过制定策略来检查单个资源,因此我将在控制器中执行此操作。