Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel prevent users from editing/viewing other users' resources

Tags:

php

laravel

In my laravel app I have multiple user accounts who have resources that are assigned to them. Say, for example, a "payment". To edit or view a payment a user would visit the /payment/edit/{payment} route (where payment is the payment ID).

Although I have an auth filter to stop un-logged in users from accessing this page there is nothing to stop, for example, user 1 from editing user 2's payment.

Is there a filter I can user that checks which user a payment (or any other resource) belongs to prevent this kind of issue?

[I am using Laravel's model bindings which automatically fetches the model specified by the route rather than me get it in the controller using eloquent.]

like image 651
harryg Avatar asked Mar 20 '23 02:03

harryg


2 Answers

No such filter exists by default, however you can easily create one (depending on how your database is set up). Within app/filters.php, you may do something like this:

Route::filter('restrictPermission', function($route)
{
    $payment_id = $route->parameter('payment');

    if (!Auth::user()->payments()->find($payment_id)) return Redirect::to('/');
});

This compares the currently logged in user's payment_id (in your database) to the {payment} argument passed into the route. Obviously, depending on how your database is set up (for instance if the payment_id is in a separate table) you need to change the conditional.

Then, apply the filter to your route:

Route::get('/payment/edit/{payment}', array('before' => 'restrictPermission'));
like image 143
seeARMS Avatar answered Mar 27 '23 16:03

seeARMS


One way is to place a where statement in every relevant query. Although not very pretty, it works.

$payment = Payment::where('user_id', '=', Auth::user()->id)->find($id);

It's also possible to use url filters like seeARMS is suggesting, however I think it's not very elegant. The most logical place to nest such logic is in the model itself. One possibility is to use model events, but this gives you only the option to intercept update, insert or delete statements, not selects. This might change in the future. Maybe you could use boot() event, but I'm not sure if this is gonna work.

Last but not least you could use query scopes.

class Payment extends Eloquent {

    public function scopeAuthuser($query)
    {
        return $query->where('user_id', '=', Auth::user()->id);
    }
}

and in the queries you attach the scope

Payment::authuser()->find($id);

You could do this on a base Model and extend from it, so you have that method in all your relevant models.

like image 35
aebersold Avatar answered Mar 27 '23 16:03

aebersold