简体   繁体   中英

Laravel prevent users from editing/viewing other users' resources

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.]

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

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.

Consider using Laravel Policies: https://laravel.com/docs/6.x/authorization#policy-methods

<?php

namespace App\Policies;

use App\Post;
use App\User;

class PostPolicy
{
    /**
     * Determine if the given post can be updated by the user.
     *
     * @param  \App\User  $user
     * @param  \App\Post  $post
     * @return bool
     */
    public function update(User $user, Post $post)
    {
        return $user->id === $post->user_id;
    }
}

By policies you can control if given record could be edited by logged user or not.

Cheers!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM