McGo
McGo

Reputation: 4157

Row based Access control for Laravel Results

I'd like to setup a row based access control on my laravel application (currently 5.2, waiting for 5.5 lts). This could be done in the controller, but I was wondering if there is a way to do it a bit deeper in the framework.

Let's say there are these models:

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

The currently logged in user should only see those devices and faq documents that belong to their projects.

My current attempt is to do this in the controller. Get the current user, check for a generic "access all project" permission and - if not present - join the project for the asked model to limit the result. This has to be replicated on all queries that are running for this model and I am feeling that this kind of redundancy is not perfect.

Is there a way to create something like a interface trait with a method withAccess() that forces those models (Device and FAQ Document in my example) to implement this method and do the query once on the model definition?

Upvotes: 1

Views: 1147

Answers (1)

martincarlin87
martincarlin87

Reputation: 11042

One thing I can think off is to use a reusable scope for each model.

e.g.

In your controller:

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

and in your Device model:

public function scopeViewableDevices($query)
{

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

}

The query might be wrong compared to how your data is stored and the logic you are trying to achieve but what I am meaning in the scope is to find the project for the device, then find the user for the project and see if it belongs to the logged in user.

For this to work you'd need to setup a project relationship in the Device model and a user relationship in the Project model.

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

The relationships might be off, I always get the order mixed up but I generally use php artisan tinker to make sure that they work.

Scopes Docs

Relationship Docs

The only other thing I'd suggest is to make sure you have indexes (indices?) on your foreign key columns, e.g. project_id, user_id and any others, they will help to speed up your queries, especially if your tables are quite large.

Upvotes: 3

Related Questions