Reputation: 4157
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
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.
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