Laravel 5: "Owner" multi-model middleware

I want to create middleware to check if an authenticated user is the owner of an item. For one model, the code is simple and looks something like this:

    <?php namespace App\Http\Middleware;

    use Closure;

    class Owner {

        public function handle($request, Closure $next)
        {
            $id = $request->segments()[1]; //get the id parameter
            $model = Model::find($id); // find the model from DB

            if(!$item)
              return 'not found'; //if item not found

            //check if authenticated user is owner
            if($item->user_id == \Auth::id()){ 
              return $next($request);
            }else{
              return 'not allowed';
            }
        }
    }

      

Now let's say that I have multiple models (ModelX, ModelY, ModelZ) and I don't want to rewrite the middleware processing function multiple times. How would I embed a reference model in the middleware so that it can host multiple models from my application?

+3


source to share


2 answers


You can use route / model binding middleware options. Let's assume you have a message resource.

You determine the route. The middle software gets a parameter describing the resource with which you want to check ownership.

Route::get('/post/{post}', ['middleware' => 'owner:post', 'as' => 'post', 'uses' => 'PostController@showPost']);

      

Then you will bind your model to RouteServiceProvider.php:



$router->bind('post', function ($value) {
   return Post::where('id', $value)->firstOrFail();
});

      

Finally, you would make middleware. It is important to know that the binding is made available in the request object as $ request-> post. Because you pass the name of the resource to the middleware, it becomes the third parameter in the descriptor method.

public function handle($request, Closure $next, $resource)
{
    if ($request->{$resource}->user_id == \Auth::id()) {
      return $next($request);
    }
    return response('not allowed.', 401);
}

      

I suppose you could also find the resource name programmatically, but using this method, your resource name and your route might be different.

+3


source


You can use route and middleware options :

Retrieves middleware ( app/Http/Middleware/AbortIfNotOwner.php

):

<?php

namespace App\Http\Middleware;

use Closure;

class AbortIfNotOwner
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @param  string    $resourceName
     * @return mixed
     */
    public function handle($request, Closure $next, $resourceName)
    {
        $resourceId = $request->route()->parameter($resourceName);

        $userId = \DB::table($resourceName)->find($resourceId)->user_id;

        if ($request->user()->id != $userId) {
            abort(403, 'Unauthorized action.');
        }

        return $next($request);
    }
}

      

Inside app\Http\Kernel.php

:

protected $routeMiddleware = [
     'owner' => 'App\Http\Middleware\AbortIfNotOwner',
];

      



Inside the route file ( app/Http/routes.php

):

Route::group(['middleware' => ['owner:articles']], function() {
    // your route
});

      

And maybe call it in your controller:

public function __construct()
{
    $this->middleware('owner:articles', ['only' => ['edit', 'update']]);
}

      

+2


source







All Articles