Laravel结果的基于行的访问控制

时间:2017-04-03 08:12:31

标签: php laravel laravel-5 eloquent

我想在我的laravel应用程序上设置基于行的访问控制(目前为5.​​2,等待5.5 lts)。这可以在控制器中完成,但我想知道是否有一种方法可以在框架中更深入地完成它。

假设有这些模型:

P - project
U - user (assigned to many projects)
D - Device (assigned to one project)
F - FAQ document (assigned to one project)

当前登录的用户应该只能看到属于他们项目的那些设备和常见问题解答文档。

我目前的尝试是在控制器中执行此操作。获取当前用户,检查通用“访问所有项目”权限,如果不存在,则加入项目以获取要求的模型以限制结果。这必须在为此模型运行的所有查询上进行复制,我觉得这种冗余并不完美。

有没有办法用方法withAccess()创建类似接口特征的东西,强制这些模型(我的例子中的Device和FAQ Document)实现这个方法并在模型定义上执行一次查询? / p>

1 个答案:

答案 0 :(得分:3)

我能想到的一件事是为每个模型使用可重复使用的范围。

e.g。

在您的控制器中:

$devices = Device::ViewableDevices()->get();

并在您的Device模型中:

public function scopeViewableDevices($query)
{

    return $query->whereHas('project', function($query) {
        $query->whereHas('user', function($query) {
            $query->where('user_id', Auth::user()->id);
        }
    });

}

与您的数据存储方式和您尝试实现的逻辑相比,查询可能是错误的,但我在范围内的意思是找到设备的项目,然后查找项目的用户并查看是否它属于登录用户。

为此,您需要在project模型中设置Device关系,并在user模型中设置Project关系。

e.g。

// Device.php
public function project() {
    return $this->hasOne('App\Project', 'id', 'project_id');
}

// Project.php
public function user() {
    return $this->belongsTo('App\User', 'id', 'user_id');
}

关系可能已关闭,我总是将订单混淆但我通常使用php artisan tinker来确保它们有效。

Scopes Docs

Relationship Docs

我建议的另一件事是确保你的外键列上有索引(索引?),例如project_iduser_id以及其他任何内容,它们都有助于加快查询速度,尤其是在您的桌子非常大的情况下。